summaryrefslogtreecommitdiffstats
path: root/generic/tclScan.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclScan.c')
-rw-r--r--generic/tclScan.c591
1 files changed, 220 insertions, 371 deletions
diff --git a/generic/tclScan.c b/generic/tclScan.c
index 54f9b78..4dfc2d6 100644
--- a/generic/tclScan.c
+++ b/generic/tclScan.c
@@ -7,8 +7,6 @@
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tclScan.c,v 1.18 2005/07/21 14:38:51 dkf Exp $
*/
#include "tclInt.h"
@@ -22,14 +20,8 @@
#define SCAN_UNSIGNED 0x4 /* Read an unsigned value. */
#define SCAN_WIDTH 0x8 /* A width value was supplied. */
-#define SCAN_SIGNOK 0x10 /* A +/- character is allowed. */
-#define SCAN_NODIGITS 0x20 /* No digits have been scanned. */
-#define SCAN_NOZERO 0x40 /* No zero digits have been scanned. */
-#define SCAN_XOK 0x80 /* An 'x' is allowed. */
-#define SCAN_PTOK 0x100 /* Decimal point is allowed. */
-#define SCAN_EXPOK 0x200 /* An exponent is allowed. */
-
#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
@@ -51,11 +43,11 @@ typedef struct CharSet {
* Declarations for functions used only in this file.
*/
-static char * BuildCharSet _ANSI_ARGS_((CharSet *cset, char *format));
-static int CharInSet _ANSI_ARGS_((CharSet *cset, int ch));
-static void ReleaseCharSet _ANSI_ARGS_((CharSet *cset));
-static int ValidateFormat _ANSI_ARGS_((Tcl_Interp *interp, char *format,
- int numVars, int *totalVars));
+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);
/*
*----------------------------------------------------------------------
@@ -75,14 +67,14 @@ static int ValidateFormat _ANSI_ARGS_((Tcl_Interp *interp, char *format,
*----------------------------------------------------------------------
*/
-static char *
-BuildCharSet(cset, format)
- CharSet *cset;
- char *format; /* Points to first char of set. */
+static const char *
+BuildCharSet(
+ CharSet *cset,
+ const char *format) /* Points to first char of set. */
{
Tcl_UniChar ch, start;
int offset, nranges;
- char *end;
+ const char *end;
memset(cset, 0, sizeof(CharSet));
@@ -109,10 +101,9 @@ BuildCharSet(cset, format)
end += Tcl_UtfToUniChar(end, &ch);
}
- cset->chars = (Tcl_UniChar *) ckalloc(sizeof(Tcl_UniChar)
- * (end - format - 1));
+ cset->chars = ckalloc(sizeof(Tcl_UniChar) * (end - format - 1));
if (nranges > 0) {
- cset->ranges = (struct Range *) ckalloc(sizeof(struct Range)*nranges);
+ cset->ranges = ckalloc(sizeof(struct Range) * nranges);
} else {
cset->ranges = NULL;
}
@@ -187,13 +178,14 @@ BuildCharSet(cset, format)
*/
static int
-CharInSet(cset, c)
- CharSet *cset;
- int c; /* Character to test, passed as int because of
+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;
@@ -202,8 +194,7 @@ CharInSet(cset, c)
}
if (!match) {
for (i = 0; i < cset->nranges; i++) {
- if ((cset->ranges[i].start <= ch)
- && (ch <= cset->ranges[i].end)) {
+ if ((cset->ranges[i].start <= ch) && (ch <= cset->ranges[i].end)) {
match = 1;
break;
}
@@ -229,12 +220,12 @@ CharInSet(cset, c)
*/
static void
-ReleaseCharSet(cset)
- CharSet *cset;
+ReleaseCharSet(
+ CharSet *cset)
{
- ckfree((char *)cset->chars);
+ ckfree(cset->chars);
if (cset->ranges) {
- ckfree((char *)cset->ranges);
+ ckfree(cset->ranges);
}
}
@@ -256,22 +247,24 @@ ReleaseCharSet(cset)
*/
static int
-ValidateFormat(interp, format, numVars, totalSubs)
- Tcl_Interp *interp; /* Current interpreter. */
- char *format; /* The format string. */
- int numVars; /* The number of variables passed to the scan
+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
+ int *totalSubs) /* The number of variables that will be
* required. */
{
-#define STATIC_LIST_SIZE 16
int gotXpg, gotSequential, value, i, flags;
char *end;
Tcl_UniChar ch;
- int staticAssign[STATIC_LIST_SIZE];
- int *nassign = staticAssign;
- int objIndex, xpgSize, nspace = STATIC_LIST_SIZE;
+ 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
@@ -279,10 +272,6 @@ ValidateFormat(interp, format, numVars, totalSubs)
* is multiply assigned or left unassigned.
*/
- if (numVars > nspace) {
- nassign = (int*)ckalloc(sizeof(int) * numVars);
- nspace = numVars;
- }
for (i = 0; i < nspace; i++) {
nassign[i] = 0;
}
@@ -307,14 +296,14 @@ ValidateFormat(interp, format, numVars, totalSubs)
goto xpgCheckDone;
}
- if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
+ 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. */
+ value = strtoul(format-1, &end, 10); /* INTL: "C" locale. */
if (*end != '$') {
goto notXpg;
}
@@ -343,9 +332,10 @@ ValidateFormat(interp, format, numVars, totalSubs)
gotSequential = 1;
if (gotXpg) {
mixedXPG:
- Tcl_SetResult(interp,
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
"cannot mix \"%\" and \"%n$\" conversion specifiers",
- TCL_STATIC);
+ -1));
+ Tcl_SetErrorCode(interp, "TCL", "FORMAT", "MIXEDSPECTYPES", NULL);
goto error;
}
@@ -354,8 +344,8 @@ ValidateFormat(interp, format, numVars, totalSubs)
* Parse any width specifier.
*/
- if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
- value = strtoul(format-1, &format, 10); /* INTL: "C" locale. */
+ 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);
}
@@ -366,6 +356,12 @@ ValidateFormat(interp, format, numVars, totalSubs)
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':
@@ -383,9 +379,10 @@ ValidateFormat(interp, format, numVars, totalSubs)
switch (ch) {
case 'c':
if (flags & SCAN_WIDTH) {
- Tcl_SetResult(interp,
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
"field width may not be specified in %c conversion",
- TCL_STATIC);
+ -1));
+ Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADWIDTH", NULL);
goto error;
}
/*
@@ -393,12 +390,15 @@ ValidateFormat(interp, format, numVars, totalSubs)
*/
case 'n':
case 's':
- if (flags & SCAN_LONGER) {
- invalidLonger:
+ if (flags & (SCAN_LONGER|SCAN_BIG)) {
+ invalidFieldSize:
buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
- Tcl_AppendResult(interp,
- "'l' modifier may not be specified in %", buf,
- " conversion", NULL);
+ 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;
}
/*
@@ -406,19 +406,30 @@ ValidateFormat(interp, format, numVars, totalSubs)
*/
case 'd':
case 'e':
+ case 'E':
case 'f':
case 'g':
+ case 'G':
case 'i':
case 'o':
- case 'u':
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) {
- goto invalidLonger;
+ if (flags & (SCAN_LONGER|SCAN_BIG)) {
+ goto invalidFieldSize;
}
if (*format == '\0') {
goto badSet;
@@ -444,18 +455,19 @@ ValidateFormat(interp, format, numVars, totalSubs)
}
break;
badSet:
- Tcl_SetResult(interp, "unmatched [ in format string",
- TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "unmatched [ in format string", -1));
+ Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BRACKET", NULL);
goto error;
default:
- {
- char buf[TCL_UTF_MAX+1];
-
- buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
- Tcl_AppendResult(interp, "bad scan conversion character \"",
- buf, "\"", NULL);
- goto error;
- }
+ 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) {
@@ -469,17 +481,10 @@ ValidateFormat(interp, format, numVars, totalSubs)
if (xpgSize) {
nspace = xpgSize;
} else {
- nspace += STATIC_LIST_SIZE;
- }
- if (nassign == staticAssign) {
- nassign = (void *)ckalloc(nspace * sizeof(int));
- for (i = 0; i < STATIC_LIST_SIZE; ++i) {
- nassign[i] = staticAssign[i];
- }
- } else {
- nassign = (void *)ckrealloc((void *)nassign,
- nspace * sizeof(int));
+ nspace += 16; /* formerly STATIC_LIST_SIZE */
}
+ nassign = TclStackRealloc(interp, nassign,
+ nspace * sizeof(int));
for (i = value; i < nspace; i++) {
nassign[i] = 0;
}
@@ -505,9 +510,10 @@ ValidateFormat(interp, format, numVars, totalSubs)
}
for (i = 0; i < numVars; i++) {
if (nassign[i] > 1) {
- Tcl_SetResult(interp,
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
"variable is assigned by multiple \"%n$\" conversion specifiers",
- TCL_STATIC);
+ -1));
+ Tcl_SetErrorCode(interp, "TCL", "FORMAT", "POLYASSIGNED", NULL);
goto error;
} else if (!xpgSize && (nassign[i] == 0)) {
/*
@@ -515,34 +521,32 @@ ValidateFormat(interp, format, numVars, totalSubs)
* and/or numVars != 0), then too many vars were given
*/
- Tcl_SetResult(interp,
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
"variable is not assigned by any conversion specifiers",
- TCL_STATIC);
+ -1));
+ Tcl_SetErrorCode(interp, "TCL", "FORMAT", "UNASSIGNED", NULL);
goto error;
}
}
- if (nassign != staticAssign) {
- ckfree((char *)nassign);
- }
+ TclStackFree(interp, nassign);
return TCL_OK;
badIndex:
if (gotXpg) {
- Tcl_SetResult(interp, "\"%n$\" argument index out of range",
- TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "\"%n$\" argument index out of range", -1));
+ Tcl_SetErrorCode(interp, "TCL", "FORMAT", "INDEXRANGE", NULL);
} else {
- Tcl_SetResult(interp,
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
"different numbers of variable names and field specifiers",
- TCL_STATIC);
+ -1));
+ Tcl_SetErrorCode(interp, "TCL", "FORMAT", "FIELDVARMISMATCH", NULL);
}
error:
- if (nassign != staticAssign) {
- ckfree((char *)nassign);
- }
+ TclStackFree(interp, nassign);
return TCL_ERROR;
-#undef STATIC_LIST_SIZE
}
/*
@@ -564,26 +568,20 @@ ValidateFormat(interp, format, numVars, totalSubs)
/* ARGSUSED */
int
-Tcl_ScanObjCmd(dummy, interp, objc, objv)
- ClientData dummy; /* Not used. */
- Tcl_Interp *interp; /* Current interpreter. */
- int objc; /* Number of arguments. */
- Tcl_Obj *CONST objv[]; /* Argument objects. */
+Tcl_ScanObjCmd(
+ ClientData dummy, /* Not used. */
+ Tcl_Interp *interp, /* Current interpreter. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* Argument objects. */
{
- char *format;
+ const char *format;
int numVars, nconversions, totalVars = -1;
int objIndex, offset, i, result, code;
long value;
- char *string, *end, *baseString;
+ const char *string, *end, *baseString;
char op = 0;
- int base = 0;
- int underflow = 0;
- size_t width;
- long (*fn) _ANSI_ARGS_((char*,void*,int)) = NULL;
-#ifndef TCL_WIDE_INT_IS_LONG
- Tcl_WideInt (*lfn) _ANSI_ARGS_((char*,void*,int)) = NULL;
+ int width, underflow = 0;
Tcl_WideInt wideValue;
-#endif
Tcl_UniChar ch, sch;
Tcl_Obj **objs = NULL, *objPtr = NULL;
int flags;
@@ -593,7 +591,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv,
- "string format ?varName varName ...?");
+ "string format ?varName ...?");
return TCL_ERROR;
}
@@ -613,7 +611,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
*/
if (totalVars > 0) {
- objs = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj*) * totalVars);
+ objs = ckalloc(sizeof(Tcl_Obj *) * totalVars);
for (i = 0; i < totalVars; i++) {
objs[i] = NULL;
}
@@ -631,6 +629,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
objIndex = 0;
nconversions = 0;
while (*format != '\0') {
+ int parseFlag = TCL_PARSE_NO_WHITESPACE;
format += Tcl_UtfToUniChar(format, &ch);
flags = 0;
@@ -678,9 +677,10 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
flags |= SCAN_SUPPRESS;
format += Tcl_UtfToUniChar(format, &ch);
} else if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
- value = strtoul(format-1, &end, 10); /* INTL: "C" locale. */
- if (*end == '$') {
- format = end+1;
+ 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;
}
@@ -691,7 +691,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
*/
if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
- width = strtoul(format-1, &format, 10); /* INTL: "C" locale. */
+ width = (int) strtoul(format-1, (char **) &format, 10);/* INTL: "C" locale. */
format += Tcl_UtfToUniChar(format, &ch);
} else {
width = 0;
@@ -703,6 +703,12 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
switch (ch) {
case 'l':
+ if (*format == 'l') {
+ flags |= SCAN_BIG;
+ format += 1;
+ format += Tcl_UtfToUniChar(format, &ch);
+ break;
+ }
case 'L':
flags |= SCAN_LONGER;
/*
@@ -721,6 +727,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
if (!(flags & SCAN_SUPPRESS)) {
objPtr = Tcl_NewIntObj(string - baseString);
Tcl_IncrRefCount(objPtr);
+ CLANG_ASSERT(objs);
objs[objIndex++] = objPtr;
}
nconversions++;
@@ -728,49 +735,36 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
case 'd':
op = 'i';
- base = 10;
- fn = (long (*) _ANSI_ARGS_((char*,void*,int)))strtol;
-#ifndef TCL_WIDE_INT_IS_LONG
- lfn = (Tcl_WideInt (*)_ANSI_ARGS_((char*,void*,int)))strtoll;
-#endif
+ parseFlag |= TCL_PARSE_DECIMAL_ONLY;
break;
case 'i':
op = 'i';
- base = 0;
- fn = (long (*)_ANSI_ARGS_((char*,void*,int)))strtol;
-#ifndef TCL_WIDE_INT_IS_LONG
- lfn = (Tcl_WideInt (*)_ANSI_ARGS_((char*,void*,int)))strtoll;
-#endif
+ parseFlag |= TCL_PARSE_SCAN_PREFIXES;
break;
case 'o':
op = 'i';
- base = 8;
- fn = (long (*)_ANSI_ARGS_((char*,void*,int)))strtoul;
-#ifndef TCL_WIDE_INT_IS_LONG
- lfn = (Tcl_WideInt (*)_ANSI_ARGS_((char*,void*,int)))strtoull;
-#endif
+ parseFlag |= TCL_PARSE_OCTAL_ONLY | TCL_PARSE_SCAN_PREFIXES;
break;
case 'x':
+ case 'X':
op = 'i';
- base = 16;
- fn = (long (*)_ANSI_ARGS_((char*,void*,int)))strtoul;
-#ifndef TCL_WIDE_INT_IS_LONG
- lfn = (Tcl_WideInt (*)_ANSI_ARGS_((char*,void*,int)))strtoull;
-#endif
+ parseFlag |= TCL_PARSE_HEXADECIMAL_ONLY;
+ break;
+ case 'b':
+ op = 'i';
+ parseFlag |= TCL_PARSE_BINARY_ONLY;
break;
case 'u':
op = 'i';
- base = 10;
+ parseFlag |= TCL_PARSE_DECIMAL_ONLY;
flags |= SCAN_UNSIGNED;
- fn = (long (*)_ANSI_ARGS_((char*,void*,int)))strtoul;
-#ifndef TCL_WIDE_INT_IS_LONG
- lfn = (Tcl_WideInt (*)_ANSI_ARGS_((char*,void*,int)))strtoull;
-#endif
break;
case 'f':
case 'e':
+ case 'E':
case 'g':
+ case 'G':
op = 'f';
break;
@@ -828,7 +822,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
*/
if (width == 0) {
- width = (size_t) ~0;
+ width = ~0;
}
end = string;
while (*end != '\0') {
@@ -844,6 +838,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
if (!(flags & SCAN_SUPPRESS)) {
objPtr = Tcl_NewStringObj(string, end-string);
Tcl_IncrRefCount(objPtr);
+ CLANG_ASSERT(objs);
objs[objIndex++] = objPtr;
}
string = end;
@@ -853,7 +848,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
CharSet cset;
if (width == 0) {
- width = (size_t) ~0;
+ width = ~0;
}
end = string;
@@ -894,6 +889,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
if (!(flags & SCAN_SUPPRESS)) {
objPtr = Tcl_NewIntObj((int)sch);
Tcl_IncrRefCount(objPtr);
+ CLANG_ASSERT(objs);
objs[objIndex++] = objPtr;
}
break;
@@ -902,152 +898,60 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
/*
* Scan an unsigned or signed integer.
*/
-
- if ((width == 0) || (width > sizeof(buf) - 1)) {
- width = sizeof(buf) - 1;
+ objPtr = Tcl_NewLongObj(0);
+ Tcl_IncrRefCount(objPtr);
+ if (width == 0) {
+ width = ~0;
}
- flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO;
- for (end = buf; width > 0; width--) {
- switch (*string) {
- /*
- * The 0 digit has special meaning at the beginning of a
- * number. If we are unsure of the base, it indicates that
- * we are in base 8 or base 16 (if it is followed by an
- * 'x').
- *
- * 8.1 - 8.3.4 incorrectly handled 0x... base-16 cases for
- * %x by not reading the 0x as the auto-prelude for
- * base-16. [Bug #495213]
- */
- case '0':
- if (base == 0) {
- base = 8;
- flags |= SCAN_XOK;
- }
- if (base == 16) {
- flags |= SCAN_XOK;
- }
- if (flags & SCAN_NOZERO) {
- flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO);
- } else {
- flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
- }
- goto addToInt;
-
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7':
- if (base == 0) {
- base = 10;
- }
- flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
- goto addToInt;
-
- case '8': case '9':
- if (base == 0) {
- base = 10;
- }
- if (base <= 8) {
- break;
- }
- flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
- goto addToInt;
-
- case 'A': case 'B': case 'C':
- case 'D': case 'E': case 'F':
- case 'a': case 'b': case 'c':
- case 'd': case 'e': case 'f':
- if (base <= 10) {
- break;
- }
- flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
- goto addToInt;
-
- case '+': case '-':
- if (flags & SCAN_SIGNOK) {
- flags &= ~SCAN_SIGNOK;
- goto addToInt;
+ 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;
}
- break;
-
- case 'x': case 'X':
- if ((flags & SCAN_XOK) && (end == buf+1)) {
- base = 16;
- flags &= ~SCAN_XOK;
- goto addToInt;
+ } else {
+ if (end == string + width) {
+ underflow = 1;
}
- break;
- }
-
- /*
- * We got an illegal character so we are done accumulating.
- */
-
- break;
-
- addToInt:
- /*
- * Add the character to the temporary buffer.
- */
-
- *end++ = *string++;
- if (*string == '\0') {
- break;
- }
- }
-
- /*
- * Check to see if we need to back up because we only got a sign
- * or a trailing x after a 0.
- */
-
- if (flags & SCAN_NODIGITS) {
- if (*string == '\0') {
- underflow = 1;
}
goto done;
- } else if (end[-1] == 'x' || end[-1] == 'X') {
- end--;
- string--;
}
-
- /*
- * Scan the value from the temporary buffer. If we are returning a
- * large unsigned value, we have to convert it back to a string
- * since Tcl only supports signed values.
- */
-
- if (!(flags & SCAN_SUPPRESS)) {
- *end = '\0';
-#ifndef TCL_WIDE_INT_IS_LONG
- if (flags & SCAN_LONGER) {
- wideValue = (Tcl_WideInt) (*lfn)(buf, NULL, base);
- if ((flags & SCAN_UNSIGNED) && (wideValue < 0)) {
- /* INTL: ISO digit */
- sprintf(buf, "%" TCL_LL_MODIFIER "u",
- (Tcl_WideUInt)wideValue);
- objPtr = Tcl_NewStringObj(buf, -1);
- } else {
- objPtr = Tcl_NewWideIntObj(wideValue);
+ 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 {
-#endif /* !TCL_WIDE_INT_IS_LONG */
- value = (long) (*fn)(buf, NULL, base);
- if ((flags & SCAN_UNSIGNED) && (value < 0)) {
- sprintf(buf, "%lu", value); /* INTL: ISO digit */
- objPtr = Tcl_NewStringObj(buf, -1);
- } else if ((flags & SCAN_LONGER)
- || (unsigned long) value > UINT_MAX) {
- objPtr = Tcl_NewLongObj(value);
+ Tcl_SetWideIntObj(objPtr, wideValue);
+ }
+ } else if (!(flags & SCAN_BIG)) {
+ if (TclGetLongFromObj(NULL, objPtr, &value) != TCL_OK) {
+ if (TclGetString(objPtr)[0] == '-') {
+ value = LONG_MIN;
} else {
- objPtr = Tcl_NewIntObj(value);
+ value = LONG_MAX;
}
-#ifndef TCL_WIDE_INT_IS_LONG
}
-#endif
- Tcl_IncrRefCount(objPtr);
- objs[objIndex++] = objPtr;
+ 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':
@@ -1055,105 +959,45 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
* Scan a floating point number
*/
- if ((width == 0) || (width > sizeof(buf) - 1)) {
- width = sizeof(buf) - 1;
+ objPtr = Tcl_NewDoubleObj(0.0);
+ Tcl_IncrRefCount(objPtr);
+ if (width == 0) {
+ width = ~0;
}
- flags &= ~SCAN_LONGER;
- flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_PTOK | SCAN_EXPOK;
- for (end = buf; width > 0; width--) {
- switch (*string) {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9':
- flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS);
- goto addToFloat;
- case '+': case '-':
- if (flags & SCAN_SIGNOK) {
- flags &= ~SCAN_SIGNOK;
- goto addToFloat;
- }
- break;
- case '.':
- if (flags & SCAN_PTOK) {
- flags &= ~(SCAN_SIGNOK | SCAN_PTOK);
- goto addToFloat;
- }
- break;
- case 'e': case 'E':
- /*
- * An exponent is not allowed until there has been at
- * least one digit.
- */
-
- if ((flags & (SCAN_NODIGITS | SCAN_EXPOK)) == SCAN_EXPOK) {
- flags = (flags & ~(SCAN_EXPOK|SCAN_PTOK))
- | SCAN_SIGNOK | SCAN_NODIGITS;
- goto addToFloat;
+ 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;
}
- break;
- }
-
- /*
- * We got an illegal character so we are done accumulating.
- */
-
- break;
-
- addToFloat:
- /*
- * Add the character to the temporary buffer.
- */
-
- *end++ = *string++;
- if (*string == '\0') {
- break;
- }
- }
-
- /*
- * Check to see if we need to back up because we saw a trailing
- * 'e' or sign.
- */
-
- if (flags & SCAN_NODIGITS) {
- if (flags & SCAN_EXPOK) {
- /*
- * There were no digits at all so scanning has failed and
- * we are done.
- */
-
- if (*string == '\0') {
+ } else {
+ if (end == string + width) {
underflow = 1;
}
- goto done;
- }
-
- /*
- * We got a bad exponent ('e' and maybe a sign).
- */
-
- end--;
- string--;
- if (*end != 'e' && *end != 'E') {
- end--;
- string--;
}
- }
-
- /*
- * Scan the value from the temporary buffer.
- */
-
- if (!(flags & SCAN_SUPPRESS)) {
+ goto done;
+ } else if (flags & SCAN_SUPPRESS) {
+ Tcl_DecrRefCount(objPtr);
+ string = end;
+ } else {
double dvalue;
-
- *end = '\0';
- dvalue = TclStrToD(buf, NULL);
- objPtr = Tcl_NewDoubleObj(dvalue);
- Tcl_IncrRefCount(objPtr);
+ 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;
}
- break;
}
nconversions++;
}
@@ -1172,9 +1016,14 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
continue;
}
result++;
- if (Tcl_ObjSetVar2(interp, objv[i+3], NULL, objs[i], 0) == NULL) {
- Tcl_AppendResult(interp, "couldn't set variable \"",
- TclGetString(objv[i+3]), "\"", (char *) NULL);
+
+ /*
+ * 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]);
@@ -1200,7 +1049,7 @@ Tcl_ScanObjCmd(dummy, interp, objc, objv)
}
}
if (objs != NULL) {
- ckfree((char*) objs);
+ ckfree(objs);
}
if (code == TCL_OK) {
if (underflow && (nconversions == 0)) {