diff options
Diffstat (limited to 'generic/tclScan.c')
-rw-r--r-- | generic/tclScan.c | 202 |
1 files changed, 115 insertions, 87 deletions
diff --git a/generic/tclScan.c b/generic/tclScan.c index 229f3fa..17069eb 100644 --- a/generic/tclScan.c +++ b/generic/tclScan.c @@ -43,10 +43,10 @@ typedef struct CharSet { * Declarations for functions used only in this file. */ -static char * BuildCharSet(CharSet *cset, char *format); +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, char *format, +static int ValidateFormat(Tcl_Interp *interp, const char *format, int numVars, int *totalVars); /* @@ -67,22 +67,22 @@ static int ValidateFormat(Tcl_Interp *interp, char *format, *---------------------------------------------------------------------- */ -static char * +static const char * BuildCharSet( CharSet *cset, - char *format) /* Points to first char of set. */ + 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)); - offset = Tcl_UtfToUniChar(format, &ch); + offset = TclUtfToUniChar(format, &ch); if (ch == '^') { cset->exclude = 1; format += offset; - offset = Tcl_UtfToUniChar(format, &ch); + offset = TclUtfToUniChar(format, &ch); } end = format + offset; @@ -91,20 +91,19 @@ BuildCharSet( */ if (ch == ']') { - end += Tcl_UtfToUniChar(end, &ch); + end += TclUtfToUniChar(end, &ch); } nranges = 0; while (ch != ']') { if (ch == '-') { nranges++; } - end += Tcl_UtfToUniChar(end, &ch); + end += TclUtfToUniChar(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; } @@ -114,11 +113,11 @@ BuildCharSet( */ cset->nchars = cset->nranges = 0; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); start = ch; if (ch == ']' || ch == '-') { cset->chars[cset->nchars++] = ch; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); } while (ch != ']') { if (*format == '-') { @@ -139,7 +138,7 @@ BuildCharSet( cset->chars[cset->nchars++] = start; cset->chars[cset->nchars++] = ch; } else { - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); /* * Check to see if the range is in reverse order. @@ -157,7 +156,7 @@ BuildCharSet( } else { cset->chars[cset->nchars++] = ch; } - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); } return format; } @@ -224,9 +223,9 @@ static void ReleaseCharSet( CharSet *cset) { - ckfree((char *)cset->chars); + ckfree(cset->chars); if (cset->ranges) { - ckfree((char *)cset->ranges); + ckfree(cset->ranges); } } @@ -250,7 +249,7 @@ ReleaseCharSet( static int ValidateFormat( Tcl_Interp *interp, /* Current interpreter. */ - char *format, /* The format string. */ + 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 @@ -260,8 +259,12 @@ ValidateFormat( char *end; Tcl_UniChar ch; int objIndex, xpgSize, nspace = numVars; - int *nassign = (int *) TclStackAlloc(interp, nspace * sizeof(int)); + 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 @@ -276,20 +279,20 @@ ValidateFormat( xpgSize = objIndex = gotXpg = gotSequential = 0; while (*format != '\0') { - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); flags = 0; if (ch != '%') { continue; } - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); if (ch == '%') { continue; } if (ch == '*') { flags |= SCAN_SUPPRESS; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); goto xpgCheckDone; } @@ -305,7 +308,7 @@ ValidateFormat( goto notXpg; } format = end+1; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); gotXpg = 1; if (gotSequential) { goto mixedXPG; @@ -329,9 +332,10 @@ ValidateFormat( 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; } @@ -341,9 +345,9 @@ ValidateFormat( */ if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */ - value = strtoul(format-1, &format, 10); /* INTL: "C" locale. */ + value = strtoul(format-1, (char **) &format, 10); /* INTL: "C" locale. */ flags |= SCAN_WIDTH; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); } /* @@ -355,13 +359,13 @@ ValidateFormat( if (*format == 'l') { flags |= SCAN_BIG; format += 1; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); break; } case 'L': flags |= SCAN_LONGER; case 'h': - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); } if (!(flags & SCAN_SUPPRESS) && numVars && (objIndex >= numVars)) { @@ -375,9 +379,10 @@ ValidateFormat( 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; } /* @@ -388,9 +393,12 @@ ValidateFormat( if (flags & (SCAN_LONGER|SCAN_BIG)) { invalidFieldSize: buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; - Tcl_AppendResult(interp, - "field size 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,11 +414,13 @@ ValidateFormat( case 'o': case 'x': case 'X': + case 'b': break; case 'u': if (flags & SCAN_BIG) { - Tcl_SetResult(interp, - "unsigned bignum scans are invalid", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unsigned bignum scans are invalid", -1)); + Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADUNSIGNED",NULL); goto error; } break; @@ -424,39 +434,40 @@ ValidateFormat( if (*format == '\0') { goto badSet; } - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); if (ch == '^') { if (*format == '\0') { goto badSet; } - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); } if (ch == ']') { if (*format == '\0') { goto badSet; } - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); } while (ch != ']') { if (*format == '\0') { goto badSet; } - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); } 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) { @@ -472,7 +483,7 @@ ValidateFormat( } else { nspace += 16; /* formerly STATIC_LIST_SIZE */ } - nassign = (int *) TclStackRealloc(interp, nassign, + nassign = TclStackRealloc(interp, nassign, nspace * sizeof(int)); for (i = value; i < nspace; i++) { nassign[i] = 0; @@ -499,9 +510,10 @@ ValidateFormat( } 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)) { /* @@ -509,9 +521,10 @@ ValidateFormat( * 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; } } @@ -521,12 +534,14 @@ ValidateFormat( 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: @@ -554,16 +569,16 @@ ValidateFormat( /* ARGSUSED */ int Tcl_ScanObjCmd( - ClientData dummy, /* Not used. */ + ClientData dummy, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { - char *format; + const char *format; int numVars, nconversions, totalVars = -1; int objIndex, offset, i, result, code; long value; - CONST char *string, *end, *baseString; + const char *string, *end, *baseString; char op = 0; int width, underflow = 0; Tcl_WideInt wideValue; @@ -576,11 +591,11 @@ Tcl_ScanObjCmd( if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, - "string format ?varName varName ...?"); + "string format ?varName ...?"); return TCL_ERROR; } - format = Tcl_GetStringFromObj(objv[2], NULL); + format = Tcl_GetString(objv[2]); numVars = objc-3; /* @@ -596,13 +611,13 @@ Tcl_ScanObjCmd( */ 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; } } - string = Tcl_GetStringFromObj(objv[1], NULL); + string = Tcl_GetString(objv[1]); baseString = string; /* @@ -615,7 +630,7 @@ Tcl_ScanObjCmd( nconversions = 0; while (*format != '\0') { int parseFlag = TCL_PARSE_NO_WHITESPACE; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); flags = 0; @@ -624,13 +639,13 @@ Tcl_ScanObjCmd( */ if (Tcl_UniCharIsSpace(ch)) { - offset = Tcl_UtfToUniChar(string, &sch); + offset = TclUtfToUniChar(string, &sch); while (Tcl_UniCharIsSpace(sch)) { if (*string == '\0') { goto done; } string += offset; - offset = Tcl_UtfToUniChar(string, &sch); + offset = TclUtfToUniChar(string, &sch); } continue; } @@ -641,14 +656,14 @@ Tcl_ScanObjCmd( underflow = 1; goto done; } - string += Tcl_UtfToUniChar(string, &sch); + string += TclUtfToUniChar(string, &sch); if (ch != sch) { goto done; } continue; } - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); if (ch == '%') { goto literal; } @@ -660,13 +675,13 @@ Tcl_ScanObjCmd( if (ch == '*') { flags |= SCAN_SUPPRESS; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(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); + format += TclUtfToUniChar(format, &ch); objIndex = (int) value - 1; } } @@ -676,8 +691,8 @@ Tcl_ScanObjCmd( */ if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */ - width = (int) strtoul(format-1, &format, 10);/* INTL: "C" locale. */ - format += Tcl_UtfToUniChar(format, &ch); + width = (int) strtoul(format-1, (char **) &format, 10);/* INTL: "C" locale. */ + format += TclUtfToUniChar(format, &ch); } else { width = 0; } @@ -691,7 +706,7 @@ Tcl_ScanObjCmd( if (*format == 'l') { flags |= SCAN_BIG; format += 1; - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); break; } case 'L': @@ -700,7 +715,7 @@ Tcl_ScanObjCmd( * Fall through so we skip to the next character. */ case 'h': - format += Tcl_UtfToUniChar(format, &ch); + format += TclUtfToUniChar(format, &ch); } /* @@ -712,6 +727,7 @@ Tcl_ScanObjCmd( if (!(flags & SCAN_SUPPRESS)) { objPtr = Tcl_NewIntObj(string - baseString); Tcl_IncrRefCount(objPtr); + CLANG_ASSERT(objs); objs[objIndex++] = objPtr; } nconversions++; @@ -734,6 +750,10 @@ Tcl_ScanObjCmd( 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; @@ -779,7 +799,7 @@ Tcl_ScanObjCmd( if (!(flags & SCAN_NOSKIP)) { while (*string != '\0') { - offset = Tcl_UtfToUniChar(string, &sch); + offset = TclUtfToUniChar(string, &sch); if (!Tcl_UniCharIsSpace(sch)) { break; } @@ -806,7 +826,7 @@ Tcl_ScanObjCmd( } end = string; while (*end != '\0') { - offset = Tcl_UtfToUniChar(end, &sch); + offset = TclUtfToUniChar(end, &sch); if (Tcl_UniCharIsSpace(sch)) { break; } @@ -818,6 +838,7 @@ Tcl_ScanObjCmd( if (!(flags & SCAN_SUPPRESS)) { objPtr = Tcl_NewStringObj(string, end-string); Tcl_IncrRefCount(objPtr); + CLANG_ASSERT(objs); objs[objIndex++] = objPtr; } string = end; @@ -833,7 +854,7 @@ Tcl_ScanObjCmd( format = BuildCharSet(&cset, format); while (*end != '\0') { - offset = Tcl_UtfToUniChar(end, &sch); + offset = TclUtfToUniChar(end, &sch); if (!CharInSet(&cset, (int)sch)) { break; } @@ -864,10 +885,11 @@ Tcl_ScanObjCmd( * Scan a single Unicode character. */ - string += Tcl_UtfToUniChar(string, &sch); + string += TclUtfToUniChar(string, &sch); if (!(flags & SCAN_SUPPRESS)) { objPtr = Tcl_NewIntObj((int)sch); Tcl_IncrRefCount(objPtr); + CLANG_ASSERT(objs); objs[objIndex++] = objPtr; } break; @@ -972,6 +994,7 @@ Tcl_ScanObjCmd( } } Tcl_SetDoubleObj(objPtr, dvalue); + CLANG_ASSERT(objs); objs[objIndex++] = objPtr; string = end; } @@ -993,9 +1016,14 @@ Tcl_ScanObjCmd( 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]), "\"", 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]); @@ -1021,7 +1049,7 @@ Tcl_ScanObjCmd( } } if (objs != NULL) { - ckfree((char*) objs); + ckfree(objs); } if (code == TCL_OK) { if (underflow && (nconversions == 0)) { |