diff options
Diffstat (limited to 'generic/tclIndexObj.c')
-rw-r--r-- | generic/tclIndexObj.c | 228 |
1 files changed, 72 insertions, 156 deletions
diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index efa29eb..7decf1f 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -14,6 +14,7 @@ */ #include "tclInt.h" +#include <assert.h> /* * Prototypes for functions defined later in this file: @@ -41,7 +42,8 @@ const Tcl_ObjType tclIndexType = { FreeIndex, /* freeIntRepProc */ DupIndex, /* dupIntRepProc */ UpdateStringOfIndex, /* updateStringProc */ - NULL /* setFromAnyProc */ + NULL, /* setFromAnyProc */ + TCL_OBJTYPE_V0 }; /* @@ -54,8 +56,8 @@ const Tcl_ObjType tclIndexType = { typedef struct { void *tablePtr; /* Pointer to the table of strings */ - Tcl_Size offset; /* Offset between table entries */ - Tcl_Size index; /* Selected index into table. */ + Tcl_Size offset; /* Offset between table entries */ + Tcl_Size index; /* Selected index into table. */ } IndexRep; /* @@ -67,76 +69,7 @@ typedef struct { #define NEXT_ENTRY(table, offset) \ (&(STRING_AT(table, offset))) #define EXPAND_OF(indexRep) \ - (((indexRep)->index >= 0) ? STRING_AT((indexRep)->tablePtr, (indexRep)->offset*(indexRep)->index) : "") - -/* - *---------------------------------------------------------------------- - * - * Tcl_GetIndexFromObj -- - * - * This function looks up an object's value in a table of strings and - * returns the index of the matching string, if any. - * - * Results: - * If the value of objPtr is identical to or a unique abbreviation for - * one of the entries in tablePtr, then the return value is TCL_OK and the - * index of the matching entry is stored at *indexPtr. If there isn't a - * proper match, then TCL_ERROR is returned and an error message is left - * in interp's result (unless interp is NULL). The msg argument is used - * in the error message; for example, if msg has the value "option" then - * the error message will say something flag 'bad option "foo": must be - * ...' - * - * Side effects: - * The result of the lookup is cached as the internal rep of objPtr, so - * that repeated lookups can be done quickly. - * - *---------------------------------------------------------------------- - */ - -#ifndef TCL_NO_DEPRECATED -#undef Tcl_GetIndexFromObj -int -Tcl_GetIndexFromObj( - Tcl_Interp *interp, /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr, /* Object containing the string to lookup. */ - const char *const *tablePtr, /* Array of strings to compare against the - * value of objPtr; last entry must be NULL - * and there must not be duplicate entries. */ - const char *msg, /* Identifying word to use in error - * messages. */ - int flags, /* 0 or TCL_EXACT */ - int *indexPtr) /* Place to store resulting integer index. */ -{ - if (!(flags & TCL_INDEX_TEMP_TABLE)) { - - /* - * See if there is a valid cached result from a previous lookup (doing the - * check here saves the overhead of calling Tcl_GetIndexFromObjStruct in - * the common case where the result is cached). - */ - - const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objPtr, &tclIndexType); - - if (irPtr) { - IndexRep *indexRep = (IndexRep *)irPtr->twoPtrValue.ptr1; - - /* - * Here's hoping we don't get hit by unfortunate packing constraints - * on odd platforms like a Cray PVP... - */ - - if (indexRep->tablePtr == (void *)tablePtr - && indexRep->offset == sizeof(char *)) { - *indexPtr = indexRep->index; - return TCL_OK; - } - } - } - return Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, sizeof(char *), - msg, flags, indexPtr); -} -#endif /* TCL_NO_DEPRECATED */ + (((indexRep)->index != TCL_INDEX_NONE) ? STRING_AT((indexRep)->tablePtr, (indexRep)->offset*(indexRep)->index) : "") /* *---------------------------------------------------------------------- @@ -190,30 +123,33 @@ GetIndexFromObjList( return result; } + /* Return type is int* so caller should not be passing larger table */ + assert(objc <= INT_MAX); + /* * Build a string table from the list. */ - tablePtr = (const char **)ckalloc((objc + 1) * sizeof(char *)); + tablePtr = (const char **)Tcl_Alloc((objc + 1) * sizeof(char *)); for (t = 0; t < objc; t++) { if (objv[t] == objPtr) { /* * An exact match is always chosen, so we can stop here. */ - ckfree(tablePtr); - *indexPtr = t; + Tcl_Free((void *)tablePtr); + *indexPtr = (int) t; return TCL_OK; } - tablePtr[t] = Tcl_GetString(objv[t]); + tablePtr[t] = TclGetString(objv[t]); } tablePtr[objc] = NULL; result = Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, sizeof(char *), msg, flags | TCL_INDEX_TEMP_TABLE, indexPtr); - ckfree(tablePtr); + Tcl_Free((void *)tablePtr); return result; } @@ -255,7 +191,7 @@ Tcl_GetIndexFromObjStruct( * offset, the third plus the offset again, * etc. The last entry must be NULL and there * must not be duplicate entries. */ - int offset, /* The number of bytes between entries */ + Tcl_Size offset, /* The number of bytes between entries */ const char *msg, /* Identifying word to use in error * messages. */ int flags, /* 0, TCL_EXACT, TCL_NULL_OK or TCL_INDEX_TEMP_TABLE */ @@ -269,9 +205,8 @@ Tcl_GetIndexFromObjStruct( IndexRep *indexRep; const Tcl_ObjInternalRep *irPtr; - /* Protect against invalid values, like -1 or 0. */ - if (offset < (int)sizeof(char *)) { - offset = (int)sizeof(char *); + if (offset < (Tcl_Size) sizeof(char *)) { + return TclIndexInvalidError(interp, "struct offset", offset); } /* * See if there is a valid cached result from a previous lookup. @@ -283,7 +218,7 @@ Tcl_GetIndexFromObjStruct( indexRep = (IndexRep *)irPtr->twoPtrValue.ptr1; if ((indexRep->tablePtr == tablePtr) && (indexRep->offset == offset) - && (indexRep->index >= 0)) { + && (indexRep->index != TCL_INDEX_NONE)) { index = indexRep->index; goto uncachedDone; } @@ -346,14 +281,14 @@ Tcl_GetIndexFromObjStruct( * operation. */ - if (objPtr && (index >= 0) && !(flags & TCL_INDEX_TEMP_TABLE)) { + if (objPtr && (index != TCL_INDEX_NONE) && !(flags & TCL_INDEX_TEMP_TABLE)) { irPtr = TclFetchInternalRep(objPtr, &tclIndexType); if (irPtr) { indexRep = (IndexRep *)irPtr->twoPtrValue.ptr1; } else { Tcl_ObjInternalRep ir; - indexRep = (IndexRep*)ckalloc(sizeof(IndexRep)); + indexRep = (IndexRep*)Tcl_Alloc(sizeof(IndexRep)); ir.twoPtrValue.ptr1 = indexRep; Tcl_StoreInternalRep(objPtr, &tclIndexType, &ir); } @@ -425,6 +360,9 @@ Tcl_GetIndexFromObjStruct( } return TCL_ERROR; } +/* #define again, needed below */ +#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \ + ((Tcl_GetIndexFromObjStruct)((interp), (objPtr), (tablePtr), (offset), (msg), (flags)|(int)(sizeof(*(indexPtr))<<1), (indexPtr))) /* *---------------------------------------------------------------------- @@ -477,7 +415,7 @@ DupIndex( Tcl_Obj *dupPtr) { Tcl_ObjInternalRep ir; - IndexRep *dupIndexRep = (IndexRep *)ckalloc(sizeof(IndexRep)); + IndexRep *dupIndexRep = (IndexRep *)Tcl_Alloc(sizeof(IndexRep)); memcpy(dupIndexRep, TclFetchInternalRep(srcPtr, &tclIndexType)->twoPtrValue.ptr1, sizeof(IndexRep)); @@ -507,7 +445,7 @@ static void FreeIndex( Tcl_Obj *objPtr) { - ckfree(TclFetchInternalRep(objPtr, &tclIndexType)->twoPtrValue.ptr1); + Tcl_Free(TclFetchInternalRep(objPtr, &tclIndexType)->twoPtrValue.ptr1); objPtr->typePtr = NULL; } @@ -569,7 +507,7 @@ PrefixMatchObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - int flags = 0, result, index, i; + int flags = 0, result, dummy, i; Tcl_Size dummyLength, errorLength; Tcl_Obj *errorPtr = NULL; const char *message = "option"; @@ -579,7 +517,7 @@ PrefixMatchObjCmd( }; enum matchOptionsEnum { PRFMATCH_ERROR, PRFMATCH_EXACT, PRFMATCH_MESSAGE - }; + } index; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "?options? table string"); @@ -587,28 +525,28 @@ PrefixMatchObjCmd( } for (i = 1; i < (objc - 2); i++) { - if (Tcl_GetIndexFromObj(interp, objv[i], matchOptions, "option", 0, - &index) != TCL_OK) { + if (Tcl_GetIndexFromObjStruct(interp, objv[i], matchOptions, + sizeof(char *), "option", 0, &index) != TCL_OK) { return TCL_ERROR; } - switch ((enum matchOptionsEnum) index) { + switch (index) { case PRFMATCH_EXACT: flags |= TCL_EXACT; break; case PRFMATCH_MESSAGE: if (i > objc-4) { Tcl_SetObjResult(interp, Tcl_NewStringObj( - "missing value for -message", TCL_INDEX_NONE)); + "missing value for -message", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NOARG", (void *)NULL); return TCL_ERROR; } i++; - message = Tcl_GetString(objv[i]); + message = TclGetString(objv[i]); break; case PRFMATCH_ERROR: if (i > objc-4) { Tcl_SetObjResult(interp, Tcl_NewStringObj( - "missing value for -error", TCL_INDEX_NONE)); + "missing value for -error", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NOARG", (void *)NULL); return TCL_ERROR; } @@ -643,7 +581,7 @@ PrefixMatchObjCmd( } result = GetIndexFromObjList(interp, objPtr, tablePtr, message, flags, - &index); + &dummy); if (result != TCL_OK) { if (errorPtr != NULL && errorLength == 0) { Tcl_ResetResult(interp); @@ -662,7 +600,7 @@ PrefixMatchObjCmd( return Tcl_SetReturnOptions(interp, errorPtr); } - result = Tcl_ListObjIndex(interp, tablePtr, index, &resultPtr); + result = Tcl_ListObjIndex(interp, tablePtr, dummy, &resultPtr); if (result != TCL_OK) { return result; } @@ -708,10 +646,10 @@ PrefixAllObjCmd( return result; } resultPtr = Tcl_NewListObj(0, NULL); - string = TclGetStringFromObj(objv[2], &length); + string = Tcl_GetStringFromObj(objv[2], &length); for (t = 0; t < tableObjc; t++) { - elemString = TclGetStringFromObj(tableObjv[t], &elemLength); + elemString = Tcl_GetStringFromObj(tableObjv[t], &elemLength); /* * A prefix cannot match if it is longest. @@ -765,13 +703,13 @@ PrefixLongestObjCmd( if (result != TCL_OK) { return result; } - string = TclGetStringFromObj(objv[2], &length); + string = Tcl_GetStringFromObj(objv[2], &length); resultString = NULL; resultLength = 0; for (t = 0; t < tableObjc; t++) { - elemString = TclGetStringFromObj(tableObjv[t], &elemLength); + elemString = Tcl_GetStringFromObj(tableObjv[t], &elemLength); /* * First check if the prefix string matches the element. A prefix @@ -867,7 +805,7 @@ PrefixLongestObjCmd( void Tcl_WrongNumArgs( Tcl_Interp *interp, /* Current interpreter. */ - Tcl_Size objc, /* Number of arguments to print from objv. */ + Tcl_Size objc, /* Number of arguments to print from objv. */ Tcl_Obj *const objv[], /* Initial argument objects, which should be * included in the error message. */ const char *message) /* Error message to print after the leading @@ -880,36 +818,13 @@ Tcl_WrongNumArgs( Interp *iPtr = (Interp *)interp; const char *elementStr; - /* - * [incr Tcl] does something fairly horrific when generating error - * messages for its ensembles; it passes the whole set of ensemble - * arguments as a list in the first argument. This means that this code - * causes a problem in iTcl if it attempts to correctly quote all - * arguments, which would be the correct thing to do. We work around this - * nasty behaviour for now, and hope that we can remove it all in the - * future... - */ - -#ifndef AVOID_HACKS_FOR_ITCL - int isFirst = 1; /* Special flag used to inhibit the treating - * of the first word as a list element so the - * hacky way Itcl generates error messages for - * its ensembles will still work. [Bug - * 1066837] */ -# define MAY_QUOTE_WORD (!isFirst) -# define AFTER_FIRST_WORD (isFirst = 0) -#else /* !AVOID_HACKS_FOR_ITCL */ -# define MAY_QUOTE_WORD 1 -# define AFTER_FIRST_WORD (void) 0 -#endif /* AVOID_HACKS_FOR_ITCL */ - TclNewObj(objPtr); if (iPtr->flags & INTERP_ALTERNATE_WRONG_ARGS) { iPtr->flags &= ~INTERP_ALTERNATE_WRONG_ARGS; Tcl_AppendObjToObj(objPtr, Tcl_GetObjResult(interp)); - Tcl_AppendToObj(objPtr, " or \"", TCL_INDEX_NONE); + Tcl_AppendToObj(objPtr, " or \"", -1); } else { - Tcl_AppendToObj(objPtr, "wrong # args: should be \"", TCL_INDEX_NONE); + Tcl_AppendToObj(objPtr, "wrong # args: should be \"", -1); } /* @@ -956,12 +871,12 @@ Tcl_WrongNumArgs( elementStr = EXPAND_OF(indexRep); elemLen = strlen(elementStr); } else { - elementStr = TclGetStringFromObj(origObjv[i], &elemLen); + elementStr = Tcl_GetStringFromObj(origObjv[i], &elemLen); } flags = 0; len = TclScanElement(elementStr, elemLen, &flags); - if (MAY_QUOTE_WORD && len != elemLen) { + if (len != elemLen) { char *quotedElementStr = (char *)TclStackAlloc(interp, len + 1); len = TclConvertElement(elementStr, elemLen, @@ -972,14 +887,12 @@ Tcl_WrongNumArgs( Tcl_AppendToObj(objPtr, elementStr, elemLen); } - AFTER_FIRST_WORD; - /* * Add a space if the word is not the last one (which has a * moderately complex condition here). */ - if (i + 1 < toPrint || objc!=0 || message!=NULL) { + if (i<toPrint-1 || objc!=0 || message!=NULL) { Tcl_AppendStringsToObj(objPtr, " ", (void *)NULL); } } @@ -1008,11 +921,11 @@ Tcl_WrongNumArgs( * Quote the argument if it contains spaces (Bug 942757). */ - elementStr = TclGetStringFromObj(objv[i], &elemLen); + elementStr = Tcl_GetStringFromObj(objv[i], &elemLen); flags = 0; len = TclScanElement(elementStr, elemLen, &flags); - if (MAY_QUOTE_WORD && len != elemLen) { + if (len != elemLen) { char *quotedElementStr = (char *)TclStackAlloc(interp, len + 1); len = TclConvertElement(elementStr, elemLen, @@ -1024,8 +937,6 @@ Tcl_WrongNumArgs( } } - AFTER_FIRST_WORD; - /* * Append a space character (" ") if there is more text to follow * (either another element from objv, or the message string). @@ -1048,8 +959,6 @@ Tcl_WrongNumArgs( Tcl_AppendStringsToObj(objPtr, "\"", (void *)NULL); Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", (void *)NULL); Tcl_SetObjResult(interp, objPtr); -#undef MAY_QUOTE_WORD -#undef AFTER_FIRST_WORD } /* @@ -1081,7 +990,7 @@ Tcl_ParseArgsObjv( Tcl_Interp *interp, /* Place to store error message. */ const Tcl_ArgvInfo *argTable, /* Array of option descriptions. */ - int *objcPtr, /* Number of arguments in objv. Modified to + Tcl_Size *objcPtr, /* Number of arguments in objv. Modified to * hold # args left in objv at end. */ Tcl_Obj *const *objv, /* Array of arguments to be parsed. */ Tcl_Obj ***remObjv) /* Pointer to array of arguments that were not @@ -1103,13 +1012,13 @@ Tcl_ParseArgsObjv( * quick check for matching; use 2nd char. * because first char. will almost always be * '-'). */ - Tcl_Size srcIndex; /* Location from which to read next argument + Tcl_Size srcIndex; /* Location from which to read next argument * from objv. */ - Tcl_Size dstIndex; /* Used to keep track of current arguments + Tcl_Size dstIndex; /* Used to keep track of current arguments * being processed, primarily for error * reporting. */ - Tcl_Size objc; /* # arguments in objv still to process. */ - Tcl_Size length; /* Number of characters in current argument */ + Tcl_Size objc; /* # arguments in objv still to process. */ + Tcl_Size length; /* Number of characters in current argument */ if (remObjv != NULL) { /* @@ -1120,7 +1029,7 @@ Tcl_ParseArgsObjv( */ nrem = 1; - leftovers = (Tcl_Obj **)ckalloc((1 + *objcPtr) * sizeof(Tcl_Obj *)); + leftovers = (Tcl_Obj **)Tcl_Alloc((1 + *objcPtr) * sizeof(Tcl_Obj *)); leftovers[0] = objv[0]; } else { nrem = 0; @@ -1138,7 +1047,7 @@ Tcl_ParseArgsObjv( curArg = objv[srcIndex]; srcIndex++; objc--; - str = TclGetStringFromObj(curArg, &length); + str = Tcl_GetStringFromObj(curArg, &length); if (length > 0) { c = str[1]; } else { @@ -1206,7 +1115,7 @@ Tcl_ParseArgsObjv( (int *) infoPtr->dstPtr) == TCL_ERROR) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "expected integer argument for \"%s\" but got \"%s\"", - infoPtr->keyStr, Tcl_GetString(objv[srcIndex]))); + infoPtr->keyStr, TclGetString(objv[srcIndex]))); goto error; } srcIndex++; @@ -1217,7 +1126,7 @@ Tcl_ParseArgsObjv( goto missingArg; } *((const char **) infoPtr->dstPtr) = - Tcl_GetString(objv[srcIndex]); + TclGetString(objv[srcIndex]); srcIndex++; objc--; break; @@ -1239,7 +1148,7 @@ Tcl_ParseArgsObjv( (double *) infoPtr->dstPtr) == TCL_ERROR) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "expected floating-point argument for \"%s\" but got \"%s\"", - infoPtr->keyStr, Tcl_GetString(objv[srcIndex]))); + infoPtr->keyStr, TclGetString(objv[srcIndex]))); goto error; } srcIndex++; @@ -1262,14 +1171,21 @@ Tcl_ParseArgsObjv( break; } case TCL_ARGV_GENFUNC: { + + if (objc > INT_MAX) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "too many (%" TCL_SIZE_MODIFIER "d) arguments for TCL_ARGV_GENFUNC", objc)); + goto error; + } Tcl_ArgvGenFuncProc *handlerProc = (Tcl_ArgvGenFuncProc *) infoPtr->srcPtr; - objc = handlerProc(infoPtr->clientData, interp, objc, + int i = handlerProc(infoPtr->clientData, interp, (int) objc, &objv[srcIndex], infoPtr->dstPtr); - if (objc < 0) { + if (i < 0) { goto error; } + objc = i; break; } case TCL_ARGV_HELP: @@ -1304,7 +1220,7 @@ Tcl_ParseArgsObjv( } leftovers[nrem] = NULL; *objcPtr = nrem++; - *remObjv = (Tcl_Obj **)ckrealloc(leftovers, nrem * sizeof(Tcl_Obj *)); + *remObjv = (Tcl_Obj **)Tcl_Realloc(leftovers, nrem * sizeof(Tcl_Obj *)); return TCL_OK; /* @@ -1317,7 +1233,7 @@ Tcl_ParseArgsObjv( "\"%s\" option requires an additional argument", str)); error: if (leftovers != NULL) { - ckfree(leftovers); + Tcl_Free(leftovers); } return TCL_ERROR; } @@ -1375,7 +1291,7 @@ PrintUsage( * Now add the option information, with pretty-printing. */ - msg = Tcl_NewStringObj("Command-specific options:", TCL_INDEX_NONE); + msg = Tcl_NewStringObj("Command-specific options:", -1); for (infoPtr = argTable; infoPtr->type != TCL_ARGV_END; infoPtr++) { if ((infoPtr->type == TCL_ARGV_HELP) && (infoPtr->keyStr == NULL)) { Tcl_AppendPrintfToObj(msg, "\n%s", infoPtr->helpStr); @@ -1391,7 +1307,7 @@ PrintUsage( } numSpaces -= NUM_SPACES; } - Tcl_AppendToObj(msg, infoPtr->helpStr, TCL_INDEX_NONE); + Tcl_AppendToObj(msg, infoPtr->helpStr, -1); switch (infoPtr->type) { case TCL_ARGV_INT: Tcl_AppendPrintfToObj(msg, "\n\t\tDefault value: %d", @@ -1449,8 +1365,8 @@ TclGetCompletionCodeFromObj( && TclGetIntFromObj(NULL, value, codePtr) == TCL_OK) { return TCL_OK; } - if (Tcl_GetIndexFromObj(NULL, value, returnCodes, NULL, TCL_EXACT, - codePtr) == TCL_OK) { + if (Tcl_GetIndexFromObjStruct(NULL, value, returnCodes, + sizeof(char *), NULL, TCL_EXACT, codePtr) == TCL_OK) { return TCL_OK; } |