summaryrefslogtreecommitdiffstats
path: root/tcl8.6/generic/tclScan.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2017-09-22 18:51:12 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2017-09-22 18:51:12 (GMT)
commit3fa8e6dc88e8041b6cb88d1b1e9c05676d3346b7 (patch)
tree69afbb41089c8358615879f7cd3c4cf7997f4c7e /tcl8.6/generic/tclScan.c
parenta0e17db23c0fd7c771c0afce8cce350c98f90b02 (diff)
downloadblt-3fa8e6dc88e8041b6cb88d1b1e9c05676d3346b7.zip
blt-3fa8e6dc88e8041b6cb88d1b1e9c05676d3346b7.tar.gz
blt-3fa8e6dc88e8041b6cb88d1b1e9c05676d3346b7.tar.bz2
update to tcl/tk 8.6.7
Diffstat (limited to 'tcl8.6/generic/tclScan.c')
-rw-r--r--tcl8.6/generic/tclScan.c1079
1 files changed, 0 insertions, 1079 deletions
diff --git a/tcl8.6/generic/tclScan.c b/tcl8.6/generic/tclScan.c
deleted file mode 100644
index 3edb8be..0000000
--- a/tcl8.6/generic/tclScan.c
+++ /dev/null
@@ -1,1079 +0,0 @@
-/*
- * tclScan.c --
- *
- * This file contains the implementation of the "scan" command.
- *
- * Copyright (c) 1998 by Scriptics Corporation.
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#include "tclInt.h"
-
-/*
- * Flag values used by Tcl_ScanObjCmd.
- */
-
-#define SCAN_NOSKIP 0x1 /* Don't skip blanks. */
-#define SCAN_SUPPRESS 0x2 /* Suppress assignment. */
-#define SCAN_UNSIGNED 0x4 /* Read an unsigned value. */
-#define SCAN_WIDTH 0x8 /* A width value was supplied. */
-
-#define SCAN_LONGER 0x400 /* Asked for a wide value. */
-#define SCAN_BIG 0x800 /* Asked for a bignum value. */
-
-/*
- * The following structure contains the information associated with a
- * character set.
- */
-
-typedef struct CharSet {
- int exclude; /* 1 if this is an exclusion set. */
- int nchars;
- Tcl_UniChar *chars;
- int nranges;
- struct Range {
- Tcl_UniChar start;
- Tcl_UniChar end;
- } *ranges;
-} CharSet;
-
-/*
- * Declarations for functions used only in this file.
- */
-
-static const char * BuildCharSet(CharSet *cset, const char *format);
-static int CharInSet(CharSet *cset, int ch);
-static void ReleaseCharSet(CharSet *cset);
-static int ValidateFormat(Tcl_Interp *interp, const char *format,
- int numVars, int *totalVars);
-
-/*
- *----------------------------------------------------------------------
- *
- * BuildCharSet --
- *
- * This function examines a character set format specification and builds
- * a CharSet containing the individual characters and character ranges
- * specified.
- *
- * Results:
- * Returns the next format position.
- *
- * Side effects:
- * Initializes the charset.
- *
- *----------------------------------------------------------------------
- */
-
-static const char *
-BuildCharSet(
- CharSet *cset,
- const char *format) /* Points to first char of set. */
-{
- Tcl_UniChar ch, start;
- int offset, nranges;
- const char *end;
-
- memset(cset, 0, sizeof(CharSet));
-
- offset = Tcl_UtfToUniChar(format, &ch);
- if (ch == '^') {
- cset->exclude = 1;
- format += offset;
- offset = Tcl_UtfToUniChar(format, &ch);
- }
- end = format + offset;
-
- /*
- * Find the close bracket so we can overallocate the set.
- */
-
- if (ch == ']') {
- end += Tcl_UtfToUniChar(end, &ch);
- }
- nranges = 0;
- while (ch != ']') {
- if (ch == '-') {
- nranges++;
- }
- end += Tcl_UtfToUniChar(end, &ch);
- }
-
- cset->chars = ckalloc(sizeof(Tcl_UniChar) * (end - format - 1));
- if (nranges > 0) {
- cset->ranges = ckalloc(sizeof(struct Range) * nranges);
- } else {
- cset->ranges = NULL;
- }
-
- /*
- * Now build the character set.
- */
-
- cset->nchars = cset->nranges = 0;
- format += Tcl_UtfToUniChar(format, &ch);
- start = ch;
- if (ch == ']' || ch == '-') {
- cset->chars[cset->nchars++] = ch;
- format += Tcl_UtfToUniChar(format, &ch);
- }
- while (ch != ']') {
- if (*format == '-') {
- /*
- * This may be the first character of a range, so don't add it
- * yet.
- */
-
- start = ch;
- } else if (ch == '-') {
- /*
- * Check to see if this is the last character in the set, in which
- * case it is not a range and we should add the previous character
- * as well as the dash.
- */
-
- if (*format == ']') {
- cset->chars[cset->nchars++] = start;
- cset->chars[cset->nchars++] = ch;
- } else {
- format += Tcl_UtfToUniChar(format, &ch);
-
- /*
- * Check to see if the range is in reverse order.
- */
-
- if (start < ch) {
- cset->ranges[cset->nranges].start = start;
- cset->ranges[cset->nranges].end = ch;
- } else {
- cset->ranges[cset->nranges].start = ch;
- cset->ranges[cset->nranges].end = start;
- }
- cset->nranges++;
- }
- } else {
- cset->chars[cset->nchars++] = ch;
- }
- format += Tcl_UtfToUniChar(format, &ch);
- }
- return format;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CharInSet --
- *
- * Check to see if a character matches the given set.
- *
- * Results:
- * Returns non-zero if the character matches the given set.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-CharInSet(
- CharSet *cset,
- int c) /* Character to test, passed as int because of
- * non-ANSI prototypes. */
-{
- Tcl_UniChar ch = (Tcl_UniChar) c;
- int i, match = 0;
-
- for (i = 0; i < cset->nchars; i++) {
- if (cset->chars[i] == ch) {
- match = 1;
- break;
- }
- }
- if (!match) {
- for (i = 0; i < cset->nranges; i++) {
- if ((cset->ranges[i].start <= ch) && (ch <= cset->ranges[i].end)) {
- match = 1;
- break;
- }
- }
- }
- return (cset->exclude ? !match : match);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ReleaseCharSet --
- *
- * Free the storage associated with a character set.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-ReleaseCharSet(
- CharSet *cset)
-{
- ckfree(cset->chars);
- if (cset->ranges) {
- ckfree(cset->ranges);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ValidateFormat --
- *
- * Parse the format string and verify that it is properly formed and that
- * there are exactly enough variables on the command line.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * May place an error in the interpreter result.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ValidateFormat(
- Tcl_Interp *interp, /* Current interpreter. */
- const char *format, /* The format string. */
- int numVars, /* The number of variables passed to the scan
- * command. */
- int *totalSubs) /* The number of variables that will be
- * required. */
-{
- int gotXpg, gotSequential, value, i, flags;
- char *end;
- Tcl_UniChar ch;
- int objIndex, xpgSize, nspace = numVars;
- int *nassign = TclStackAlloc(interp, nspace * sizeof(int));
- char buf[TCL_UTF_MAX+1];
- Tcl_Obj *errorMsg; /* Place to build an error messages. Note that
- * these are messy operations because we do
- * not want to use the formatting engine;
- * we're inside there! */
-
- /*
- * Initialize an array that records the number of times a variable is
- * assigned to by the format string. We use this to detect if a variable
- * is multiply assigned or left unassigned.
- */
-
- for (i = 0; i < nspace; i++) {
- nassign[i] = 0;
- }
-
- xpgSize = objIndex = gotXpg = gotSequential = 0;
-
- while (*format != '\0') {
- format += Tcl_UtfToUniChar(format, &ch);
-
- flags = 0;
-
- if (ch != '%') {
- continue;
- }
- format += Tcl_UtfToUniChar(format, &ch);
- if (ch == '%') {
- continue;
- }
- if (ch == '*') {
- flags |= SCAN_SUPPRESS;
- format += Tcl_UtfToUniChar(format, &ch);
- goto xpgCheckDone;
- }
-
- if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
- /*
- * 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.
- */
-
- value = strtoul(format-1, &end, 10); /* INTL: "C" locale. */
- if (*end != '$') {
- goto notXpg;
- }
- format = end+1;
- format += Tcl_UtfToUniChar(format, &ch);
- gotXpg = 1;
- if (gotSequential) {
- goto mixedXPG;
- }
- objIndex = value - 1;
- if ((objIndex < 0) || (numVars && (objIndex >= numVars))) {
- goto badIndex;
- } else if (numVars == 0) {
- /*
- * In the case where no vars are specified, the user can
- * specify %9999$ legally, so we have to consider special
- * rules for growing the assign array. 'value' is guaranteed
- * to be > 0.
- */
- xpgSize = (xpgSize > value) ? xpgSize : value;
- }
- goto xpgCheckDone;
- }
-
- notXpg:
- gotSequential = 1;
- if (gotXpg) {
- mixedXPG:
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "cannot mix \"%\" and \"%n$\" conversion specifiers",
- -1));
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "MIXEDSPECTYPES", NULL);
- goto error;
- }
-
- xpgCheckDone:
- /*
- * Parse any width specifier.
- */
-
- if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
- value = strtoul(format-1, (char **) &format, 10); /* INTL: "C" locale. */
- flags |= SCAN_WIDTH;
- format += Tcl_UtfToUniChar(format, &ch);
- }
-
- /*
- * Handle any size specifier.
- */
-
- switch (ch) {
- case 'l':
- if (*format == 'l') {
- flags |= SCAN_BIG;
- format += 1;
- format += Tcl_UtfToUniChar(format, &ch);
- break;
- }
- case 'L':
- flags |= SCAN_LONGER;
- case 'h':
- format += Tcl_UtfToUniChar(format, &ch);
- }
-
- if (!(flags & SCAN_SUPPRESS) && numVars && (objIndex >= numVars)) {
- goto badIndex;
- }
-
- /*
- * Handle the various field types.
- */
-
- switch (ch) {
- case 'c':
- if (flags & SCAN_WIDTH) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "field width may not be specified in %c conversion",
- -1));
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADWIDTH", NULL);
- goto error;
- }
- /*
- * Fall through!
- */
- case 'n':
- case 's':
- if (flags & (SCAN_LONGER|SCAN_BIG)) {
- invalidFieldSize:
- buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
- errorMsg = Tcl_NewStringObj(
- "field size modifier may not be specified in %", -1);
- Tcl_AppendToObj(errorMsg, buf, -1);
- Tcl_AppendToObj(errorMsg, " conversion", -1);
- Tcl_SetObjResult(interp, errorMsg);
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADSIZE", NULL);
- goto error;
- }
- /*
- * Fall through!
- */
- case 'd':
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- case 'i':
- case 'o':
- case 'x':
- case 'X':
- case 'b':
- break;
- case 'u':
- if (flags & SCAN_BIG) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "unsigned bignum scans are invalid", -1));
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADUNSIGNED",NULL);
- goto error;
- }
- break;
- /*
- * Bracket terms need special checking
- */
- case '[':
- if (flags & (SCAN_LONGER|SCAN_BIG)) {
- goto invalidFieldSize;
- }
- if (*format == '\0') {
- goto badSet;
- }
- format += Tcl_UtfToUniChar(format, &ch);
- if (ch == '^') {
- if (*format == '\0') {
- goto badSet;
- }
- format += Tcl_UtfToUniChar(format, &ch);
- }
- if (ch == ']') {
- if (*format == '\0') {
- goto badSet;
- }
- format += Tcl_UtfToUniChar(format, &ch);
- }
- while (ch != ']') {
- if (*format == '\0') {
- goto badSet;
- }
- format += Tcl_UtfToUniChar(format, &ch);
- }
- break;
- badSet:
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "unmatched [ in format string", -1));
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BRACKET", NULL);
- goto error;
- default:
- buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
- errorMsg = Tcl_NewStringObj(
- "bad scan conversion character \"", -1);
- Tcl_AppendToObj(errorMsg, buf, -1);
- Tcl_AppendToObj(errorMsg, "\"", -1);
- Tcl_SetObjResult(interp, errorMsg);
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADTYPE", NULL);
- goto error;
- }
- if (!(flags & SCAN_SUPPRESS)) {
- if (objIndex >= nspace) {
- /*
- * Expand the nassign buffer. If we are using XPG specifiers,
- * make sure that we grow to a large enough size. xpgSize is
- * guaranteed to be at least one larger than objIndex.
- */
-
- value = nspace;
- if (xpgSize) {
- nspace = xpgSize;
- } else {
- nspace += 16; /* formerly STATIC_LIST_SIZE */
- }
- nassign = TclStackRealloc(interp, nassign,
- nspace * sizeof(int));
- for (i = value; i < nspace; i++) {
- nassign[i] = 0;
- }
- }
- nassign[objIndex]++;
- objIndex++;
- }
- }
-
- /*
- * Verify that all of the variable were assigned exactly once.
- */
-
- if (numVars == 0) {
- if (xpgSize) {
- numVars = xpgSize;
- } else {
- numVars = objIndex;
- }
- }
- if (totalSubs) {
- *totalSubs = numVars;
- }
- for (i = 0; i < numVars; i++) {
- if (nassign[i] > 1) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "variable is assigned by multiple \"%n$\" conversion specifiers",
- -1));
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "POLYASSIGNED", NULL);
- goto error;
- } else if (!xpgSize && (nassign[i] == 0)) {
- /*
- * If the space is empty, and xpgSize is 0 (means XPG wasn't used,
- * and/or numVars != 0), then too many vars were given
- */
-
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "variable is not assigned by any conversion specifiers",
- -1));
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "UNASSIGNED", NULL);
- goto error;
- }
- }
-
- TclStackFree(interp, nassign);
- return TCL_OK;
-
- badIndex:
- if (gotXpg) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "\"%n$\" argument index out of range", -1));
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "INDEXRANGE", NULL);
- } else {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "different numbers of variable names and field specifiers",
- -1));
- Tcl_SetErrorCode(interp, "TCL", "FORMAT", "FIELDVARMISMATCH", NULL);
- }
-
- error:
- TclStackFree(interp, nassign);
- return TCL_ERROR;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_ScanObjCmd --
- *
- * This function is invoked to process the "scan" Tcl command. See the
- * user documentation for details on what it does.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * See the user documentation.
- *
- *----------------------------------------------------------------------
- */
-
- /* ARGSUSED */
-int
-Tcl_ScanObjCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- const char *format;
- int numVars, nconversions, totalVars = -1;
- int objIndex, offset, i, result, code;
- long value;
- const char *string, *end, *baseString;
- char op = 0;
- int width, underflow = 0;
- Tcl_WideInt wideValue;
- Tcl_UniChar ch, sch;
- Tcl_Obj **objs = NULL, *objPtr = NULL;
- int flags;
- char buf[513]; /* Temporary buffer to hold scanned number
- * strings before they are passed to
- * strtoul. */
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 1, objv,
- "string format ?varName ...?");
- return TCL_ERROR;
- }
-
- format = Tcl_GetString(objv[2]);
- numVars = objc-3;
-
- /*
- * Check for errors in the format string.
- */
-
- if (ValidateFormat(interp, format, numVars, &totalVars) == TCL_ERROR) {
- return TCL_ERROR;
- }
-
- /*
- * Allocate space for the result objects.
- */
-
- if (totalVars > 0) {
- objs = ckalloc(sizeof(Tcl_Obj *) * totalVars);
- for (i = 0; i < totalVars; i++) {
- objs[i] = NULL;
- }
- }
-
- string = Tcl_GetString(objv[1]);
- baseString = string;
-
- /*
- * Iterate over the format string filling in the result objects until we
- * reach the end of input, the end of the format string, or there is a
- * mismatch.
- */
-
- objIndex = 0;
- nconversions = 0;
- while (*format != '\0') {
- int parseFlag = TCL_PARSE_NO_WHITESPACE;
- format += Tcl_UtfToUniChar(format, &ch);
-
- flags = 0;
-
- /*
- * If we see whitespace in the format, skip whitespace in the string.
- */
-
- if (Tcl_UniCharIsSpace(ch)) {
- offset = Tcl_UtfToUniChar(string, &sch);
- while (Tcl_UniCharIsSpace(sch)) {
- if (*string == '\0') {
- goto done;
- }
- string += offset;
- offset = Tcl_UtfToUniChar(string, &sch);
- }
- continue;
- }
-
- if (ch != '%') {
- literal:
- if (*string == '\0') {
- underflow = 1;
- goto done;
- }
- string += Tcl_UtfToUniChar(string, &sch);
- if (ch != sch) {
- goto done;
- }
- continue;
- }
-
- format += Tcl_UtfToUniChar(format, &ch);
- if (ch == '%') {
- goto literal;
- }
-
- /*
- * Check for assignment suppression ('*') or an XPG3-style assignment
- * ('%n$').
- */
-
- if (ch == '*') {
- flags |= SCAN_SUPPRESS;
- format += Tcl_UtfToUniChar(format, &ch);
- } else if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
- char *formatEnd;
- value = strtoul(format-1, &formatEnd, 10);/* INTL: "C" locale. */
- if (*formatEnd == '$') {
- format = formatEnd+1;
- format += Tcl_UtfToUniChar(format, &ch);
- objIndex = (int) value - 1;
- }
- }
-
- /*
- * Parse any width specifier.
- */
-
- if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
- width = (int) strtoul(format-1, (char **) &format, 10);/* INTL: "C" locale. */
- format += Tcl_UtfToUniChar(format, &ch);
- } else {
- width = 0;
- }
-
- /*
- * Handle any size specifier.
- */
-
- switch (ch) {
- case 'l':
- if (*format == 'l') {
- flags |= SCAN_BIG;
- format += 1;
- format += Tcl_UtfToUniChar(format, &ch);
- break;
- }
- case 'L':
- flags |= SCAN_LONGER;
- /*
- * Fall through so we skip to the next character.
- */
- case 'h':
- format += Tcl_UtfToUniChar(format, &ch);
- }
-
- /*
- * Handle the various field types.
- */
-
- switch (ch) {
- case 'n':
- if (!(flags & SCAN_SUPPRESS)) {
- objPtr = Tcl_NewIntObj(string - baseString);
- Tcl_IncrRefCount(objPtr);
- CLANG_ASSERT(objs);
- objs[objIndex++] = objPtr;
- }
- nconversions++;
- continue;
-
- case 'd':
- op = 'i';
- parseFlag |= TCL_PARSE_DECIMAL_ONLY;
- break;
- case 'i':
- op = 'i';
- parseFlag |= TCL_PARSE_SCAN_PREFIXES;
- break;
- case 'o':
- op = 'i';
- parseFlag |= TCL_PARSE_OCTAL_ONLY | TCL_PARSE_SCAN_PREFIXES;
- break;
- case 'x':
- case 'X':
- op = 'i';
- parseFlag |= TCL_PARSE_HEXADECIMAL_ONLY;
- break;
- case 'b':
- op = 'i';
- parseFlag |= TCL_PARSE_BINARY_ONLY;
- break;
- case 'u':
- op = 'i';
- parseFlag |= TCL_PARSE_DECIMAL_ONLY;
- flags |= SCAN_UNSIGNED;
- break;
-
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- op = 'f';
- break;
-
- case 's':
- op = 's';
- break;
-
- case 'c':
- op = 'c';
- flags |= SCAN_NOSKIP;
- break;
- case '[':
- op = '[';
- flags |= SCAN_NOSKIP;
- break;
- }
-
- /*
- * At this point, we will need additional characters from the string
- * to proceed.
- */
-
- if (*string == '\0') {
- underflow = 1;
- goto done;
- }
-
- /*
- * Skip any leading whitespace at the beginning of a field unless the
- * format suppresses this behavior.
- */
-
- if (!(flags & SCAN_NOSKIP)) {
- while (*string != '\0') {
- offset = Tcl_UtfToUniChar(string, &sch);
- if (!Tcl_UniCharIsSpace(sch)) {
- break;
- }
- string += offset;
- }
- if (*string == '\0') {
- underflow = 1;
- goto done;
- }
- }
-
- /*
- * Perform the requested scanning operation.
- */
-
- switch (op) {
- case 's':
- /*
- * Scan a string up to width characters or whitespace.
- */
-
- if (width == 0) {
- width = ~0;
- }
- end = string;
- while (*end != '\0') {
- offset = Tcl_UtfToUniChar(end, &sch);
- if (Tcl_UniCharIsSpace(sch)) {
- break;
- }
- end += offset;
- if (--width == 0) {
- break;
- }
- }
- if (!(flags & SCAN_SUPPRESS)) {
- objPtr = Tcl_NewStringObj(string, end-string);
- Tcl_IncrRefCount(objPtr);
- CLANG_ASSERT(objs);
- objs[objIndex++] = objPtr;
- }
- string = end;
- break;
-
- case '[': {
- CharSet cset;
-
- if (width == 0) {
- width = ~0;
- }
- end = string;
-
- format = BuildCharSet(&cset, format);
- while (*end != '\0') {
- offset = Tcl_UtfToUniChar(end, &sch);
- if (!CharInSet(&cset, (int)sch)) {
- break;
- }
- end += offset;
- if (--width == 0) {
- break;
- }
- }
- ReleaseCharSet(&cset);
-
- if (string == end) {
- /*
- * Nothing matched the range, stop processing.
- */
- goto done;
- }
- if (!(flags & SCAN_SUPPRESS)) {
- objPtr = Tcl_NewStringObj(string, end-string);
- Tcl_IncrRefCount(objPtr);
- objs[objIndex++] = objPtr;
- }
- string = end;
-
- break;
- }
- case 'c':
- /*
- * Scan a single Unicode character.
- */
-
- string += Tcl_UtfToUniChar(string, &sch);
- if (!(flags & SCAN_SUPPRESS)) {
- objPtr = Tcl_NewIntObj((int)sch);
- Tcl_IncrRefCount(objPtr);
- CLANG_ASSERT(objs);
- objs[objIndex++] = objPtr;
- }
- break;
-
- case 'i':
- /*
- * Scan an unsigned or signed integer.
- */
- objPtr = Tcl_NewLongObj(0);
- Tcl_IncrRefCount(objPtr);
- if (width == 0) {
- width = ~0;
- }
- if (TCL_OK != TclParseNumber(NULL, objPtr, NULL, string, width,
- &end, TCL_PARSE_INTEGER_ONLY | parseFlag)) {
- Tcl_DecrRefCount(objPtr);
- if (width < 0) {
- if (*end == '\0') {
- underflow = 1;
- }
- } else {
- if (end == string + width) {
- underflow = 1;
- }
- }
- goto done;
- }
- string = end;
- if (flags & SCAN_SUPPRESS) {
- Tcl_DecrRefCount(objPtr);
- break;
- }
- if (flags & SCAN_LONGER) {
- if (Tcl_GetWideIntFromObj(NULL, objPtr, &wideValue) != TCL_OK) {
- wideValue = ~(Tcl_WideUInt)0 >> 1; /* WIDE_MAX */
- if (TclGetString(objPtr)[0] == '-') {
- wideValue++; /* WIDE_MAX + 1 = WIDE_MIN */
- }
- }
- if ((flags & SCAN_UNSIGNED) && (wideValue < 0)) {
- sprintf(buf, "%" TCL_LL_MODIFIER "u",
- (Tcl_WideUInt)wideValue);
- Tcl_SetStringObj(objPtr, buf, -1);
- } else {
- Tcl_SetWideIntObj(objPtr, wideValue);
- }
- } else if (!(flags & SCAN_BIG)) {
- if (TclGetLongFromObj(NULL, objPtr, &value) != TCL_OK) {
- if (TclGetString(objPtr)[0] == '-') {
- value = LONG_MIN;
- } else {
- value = LONG_MAX;
- }
- }
- if ((flags & SCAN_UNSIGNED) && (value < 0)) {
- sprintf(buf, "%lu", value); /* INTL: ISO digit */
- Tcl_SetStringObj(objPtr, buf, -1);
- } else {
- Tcl_SetLongObj(objPtr, value);
- }
- }
- objs[objIndex++] = objPtr;
- break;
-
- case 'f':
- /*
- * Scan a floating point number
- */
-
- objPtr = Tcl_NewDoubleObj(0.0);
- Tcl_IncrRefCount(objPtr);
- if (width == 0) {
- width = ~0;
- }
- if (TCL_OK != TclParseNumber(NULL, objPtr, NULL, string, width,
- &end, TCL_PARSE_DECIMAL_ONLY | TCL_PARSE_NO_WHITESPACE)) {
- Tcl_DecrRefCount(objPtr);
- if (width < 0) {
- if (*end == '\0') {
- underflow = 1;
- }
- } else {
- if (end == string + width) {
- underflow = 1;
- }
- }
- goto done;
- } else if (flags & SCAN_SUPPRESS) {
- Tcl_DecrRefCount(objPtr);
- string = end;
- } else {
- double dvalue;
- if (Tcl_GetDoubleFromObj(NULL, objPtr, &dvalue) != TCL_OK) {
-#ifdef ACCEPT_NAN
- if (objPtr->typePtr == &tclDoubleType) {
- dvalue = objPtr->internalRep.doubleValue;
- } else
-#endif
- {
- Tcl_DecrRefCount(objPtr);
- goto done;
- }
- }
- Tcl_SetDoubleObj(objPtr, dvalue);
- CLANG_ASSERT(objs);
- objs[objIndex++] = objPtr;
- string = end;
- }
- }
- nconversions++;
- }
-
- done:
- result = 0;
- code = TCL_OK;
-
- if (numVars) {
- /*
- * In this case, variables were specified (classic scan).
- */
-
- for (i = 0; i < totalVars; i++) {
- if (objs[i] == NULL) {
- continue;
- }
- result++;
-
- /*
- * In case of multiple errors in setting variables, just report
- * the first one.
- */
-
- if (Tcl_ObjSetVar2(interp, objv[i+3], NULL, objs[i],
- (code == TCL_OK) ? TCL_LEAVE_ERR_MSG : 0) == NULL) {
- code = TCL_ERROR;
- }
- Tcl_DecrRefCount(objs[i]);
- }
- } else {
- /*
- * Here no vars were specified, we want a list returned (inline scan)
- */
-
- objPtr = Tcl_NewObj();
- for (i = 0; i < totalVars; i++) {
- if (objs[i] != NULL) {
- Tcl_ListObjAppendElement(NULL, objPtr, objs[i]);
- Tcl_DecrRefCount(objs[i]);
- } else {
- /*
- * More %-specifiers than matching chars, so we just spit out
- * empty strings for these.
- */
-
- Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewObj());
- }
- }
- }
- if (objs != NULL) {
- ckfree(objs);
- }
- if (code == TCL_OK) {
- if (underflow && (nconversions == 0)) {
- if (numVars) {
- objPtr = Tcl_NewIntObj(-1);
- } else {
- if (objPtr) {
- Tcl_SetListObj(objPtr, 0, NULL);
- } else {
- objPtr = Tcl_NewObj();
- }
- }
- } else if (numVars) {
- objPtr = Tcl_NewIntObj(result);
- }
- Tcl_SetObjResult(interp, objPtr);
- }
- return code;
-}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */