📄 tclutil.c
字号:
* If the append buffer isn't already setup and large enough to hold * the new data, set it up. */ if ((iPtr->result != iPtr->appendResult) || (iPtr->appendResult[iPtr->appendUsed] != 0) || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) { SetupAppendBuffer(iPtr, newSpace); } /* * Now go through all the argument strings again, copying them into the * buffer. */ TCL_VARARGS_START(Tcl_Interp *,arg1,argList); while (1) { string = va_arg(argList, char *); if (string == NULL) { break; } strcpy(iPtr->appendResult + iPtr->appendUsed, string); iPtr->appendUsed += strlen(string); } va_end(argList);}/* *---------------------------------------------------------------------- * * Tcl_AppendElement -- * * Convert a string to a valid Tcl list element and append it to the * result (which is ostensibly a list). * * Results: * None. * * Side effects: * The result in the interpreter given by the first argument is * extended with a list element converted from string. A separator * space is added before the converted list element unless the current * result is empty, contains the single character "{", or ends in " {". * * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */voidTcl_AppendElement(interp, string) Tcl_Interp *interp; /* Interpreter whose result is to be * extended. */ char *string; /* String to convert to list element and * add to result. */{ Interp *iPtr = (Interp *) interp; char *dst; int size; int flags; /* * If the string result is empty, move the object result to the * string result, then reset the object result. * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS. */ if (*(iPtr->result) == 0) { Tcl_SetResult(interp, TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL), TCL_VOLATILE); } /* * See how much space is needed, and grow the append buffer if * needed to accommodate the list element. */ size = Tcl_ScanElement(string, &flags) + 1; if ((iPtr->result != iPtr->appendResult) || (iPtr->appendResult[iPtr->appendUsed] != 0) || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) { SetupAppendBuffer(iPtr, size+iPtr->appendUsed); } /* * Convert the string into a list element and copy it to the * buffer that's forming, with a space separator if needed. */ dst = iPtr->appendResult + iPtr->appendUsed; if (TclNeedSpace(iPtr->appendResult, dst)) { iPtr->appendUsed++; *dst = ' '; dst++; } iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);}/* *---------------------------------------------------------------------- * * SetupAppendBuffer -- * * This procedure makes sure that there is an append buffer properly * initialized, if necessary, from the interpreter's result, and * that it has at least enough room to accommodate newSpace new * bytes of information. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */static voidSetupAppendBuffer(iPtr, newSpace) Interp *iPtr; /* Interpreter whose result is being set up. */ int newSpace; /* Make sure that at least this many bytes * of new information may be added. */{ int totalSpace; /* * Make the append buffer larger, if that's necessary, then copy the * result into the append buffer and make the append buffer the official * Tcl result. */ if (iPtr->result != iPtr->appendResult) { /* * If an oversized buffer was used recently, then free it up * so we go back to a smaller buffer. This avoids tying up * memory forever after a large operation. */ if (iPtr->appendAvl > 500) { ckfree(iPtr->appendResult); iPtr->appendResult = NULL; iPtr->appendAvl = 0; } iPtr->appendUsed = strlen(iPtr->result); } else if (iPtr->result[iPtr->appendUsed] != 0) { /* * Most likely someone has modified a result created by * Tcl_AppendResult et al. so that it has a different size. * Just recompute the size. */ iPtr->appendUsed = strlen(iPtr->result); } totalSpace = newSpace + iPtr->appendUsed; if (totalSpace >= iPtr->appendAvl) { char *new; if (totalSpace < 100) { totalSpace = 200; } else { totalSpace *= 2; } new = (char *) ckalloc((unsigned) totalSpace); strcpy(new, iPtr->result); if (iPtr->appendResult != NULL) { ckfree(iPtr->appendResult); } iPtr->appendResult = new; iPtr->appendAvl = totalSpace; } else if (iPtr->result != iPtr->appendResult) { strcpy(iPtr->appendResult, iPtr->result); } Tcl_FreeResult((Tcl_Interp *) iPtr); iPtr->result = iPtr->appendResult;}/* *---------------------------------------------------------------------- * * Tcl_FreeResult -- * * This procedure frees up the memory associated with an interpreter's * string result. It also resets the interpreter's result object. * Tcl_FreeResult is most commonly used when a procedure is about to * replace one result value with another. * * Results: * None. * * Side effects: * Frees the memory associated with interp's string result and sets * interp->freeProc to zero, but does not change interp->result or * clear error state. Resets interp's result object to an unshared * empty object. * *---------------------------------------------------------------------- */voidTcl_FreeResult(interp) Tcl_Interp *interp; /* Interpreter for which to free result. */{ Interp *iPtr = (Interp *) interp; if (iPtr->freeProc != NULL) { if ((iPtr->freeProc == TCL_DYNAMIC) || (iPtr->freeProc == (Tcl_FreeProc *) free)) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; } TclResetObjResult(iPtr);}/* *---------------------------------------------------------------------- * * Tcl_ResetResult -- * * This procedure resets both the interpreter's string and object * results. * * Results: * None. * * Side effects: * It resets the result object to an unshared empty object. It * then restores the interpreter's string result area to its default * initialized state, freeing up any memory that may have been * allocated. It also clears any error information for the interpreter. * *---------------------------------------------------------------------- */voidTcl_ResetResult(interp) Tcl_Interp *interp; /* Interpreter for which to clear result. */{ Interp *iPtr = (Interp *) interp; TclResetObjResult(iPtr); Tcl_FreeResult(interp); iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);}/* *---------------------------------------------------------------------- * * Tcl_SetErrorCode -- * * This procedure is called to record machine-readable information * about an error that is about to be returned. * * Results: * None. * * Side effects: * The errorCode global variable is modified to hold all of the * arguments to this procedure, in a list form with each argument * becoming one element of the list. A flag is set internally * to remember that errorCode has been set, so the variable doesn't * get set automatically when the error is returned. * *---------------------------------------------------------------------- */ /* VARARGS2 */voidTcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1){ va_list argList; char *string; int flags; Interp *iPtr; /* * Scan through the arguments one at a time, appending them to * $errorCode as list elements. */ iPtr = (Interp *) TCL_VARARGS_START(Tcl_Interp *,arg1,argList); flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT; while (1) { string = va_arg(argList, char *); if (string == NULL) { break; } (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode", (char *) NULL, string, flags); flags |= TCL_APPEND_VALUE; } va_end(argList); iPtr->flags |= ERROR_CODE_SET;}/* *---------------------------------------------------------------------- * * Tcl_SetObjErrorCode -- * * This procedure is called to record machine-readable information * about an error that is about to be returned. The caller should * build a list object up and pass it to this routine. * * Results: * None. * * Side effects: * The errorCode global variable is modified to be the new value. * A flag is set internally to remember that errorCode has been * set, so the variable doesn't get set automatically when the * error is returned. * *---------------------------------------------------------------------- */voidTcl_SetObjErrorCode(interp, errorObjPtr) Tcl_Interp *interp; Tcl_Obj *errorObjPtr;{ Tcl_Obj *namePtr; Interp *iPtr; namePtr = Tcl_NewStringObj("errorCode", -1); iPtr = (Interp *) interp; Tcl_ObjSetVar2(interp, namePtr, (Tcl_Obj *) NULL, errorObjPtr, TCL_GLOBAL_ONLY); iPtr->flags |= ERROR_CODE_SET; Tcl_DecrRefCount(namePtr);}/* *---------------------------------------------------------------------- * * Tcl_RegExpCompile -- * * Compile a regular expression into a form suitable for fast * matching. This procedure retains a small cache of pre-compiled * regular expressions in the interpreter, in order to avoid * compilation costs as much as possible. * * Results: * The return value is a pointer to the compiled form of string, * suitable for passing to Tcl_RegExpExec. This compiled form * is only valid up until the next call to this procedure, so * don't keep these around for a long time! If an error occurred * while compiling the pattern, then NULL is returned and an error * message is left in interp->result. * * Side effects: * The cache of compiled regexp's in interp will be modified to * hold information for string, if such information isn't already * present in the cache. * *---------------------------------------------------------------------- */Tcl_RegExpTcl_RegExpCompile(interp, string) Tcl_Interp *interp; /* For use in error reporting. */ char *string; /* String for which to produce * compiled regular expression. */{ Interp *iPtr = (Interp *) interp; int i, length; regexp *result; length = strlen(string); for (i = 0; i < NUM_REGEXPS; i++) { if ((length == iPtr->patLengths[i]) && (strcmp(string, iPtr->patterns[i]) == 0)) { /* * Move the matched pattern to the first slot in the * cache and shift the other patterns down one position. */ if (i != 0) { int j; char *cachedString; cachedString = iPtr->patterns[i]; result = iPtr->regexps[i]; for (j = i-1; j >= 0; j--) { iPtr->patterns[j+1] = iPtr->patterns[j]; iPtr->patLengths[j+1] = iPtr->patLengths[j]; iPtr->regexps[j+1] = iPtr->regexps[j]; } iPtr->patterns[0] = cachedString; iPtr->patLengths[0] = length; iPtr->regexps[0] = result; } return (Tcl_RegExp) iPtr->regexps[0]; } } /* * No match in the cache. Compile the string and add it to the * cache. */ TclRegError((char *) NULL); result = TclRegComp(string); if (TclGetRegError() != NULL) { Tcl_AppendResult(interp, "couldn't compile regular expression pattern: ", TclGetRegError(), (char *) NULL); return NULL; } if (iPtr->patterns[NUM_REGEXPS-1] != NULL) { ckfree(iPtr->patterns[NUM_REGEXPS-1]); ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]); } for (i = NUM_REGEXPS - 2; i >= 0; i--) { iPtr->patterns[i+1] = iPtr->patterns[i]; iPtr->patLengths[i+1] = iPtr->patLengths[i]; iPtr->regexps[i+1] = iPtr->regexps[i]; } iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1)); strcpy(iPtr->patterns[0], string); iPtr->patLengths[0] = length; iPtr->regexps[0] = result; return (Tcl_RegExp) result;}/* *---------------------------------------------------------------------- * * Tcl_RegExpExec -- * * Execute the regular expression matcher using a compiled form * of a regular expression and save information about any match * that is found. * * Results: * If an error occurs during the matching operation then -1 * is returned and interp->result contains an error message. * Otherwise the return value is 1 if a matching range is * found and 0 if there is no matching range. * * Side effects: * None. * *---------------------------------------------------------------------- */intTcl_RegExpExec(interp, re, string, start) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ Tcl_RegExp re; /* Compiled regular expression; must have * been returned by previous call to * Tcl_RegExpCompile. */ char *string; /* String against which to match re. */ char *start; /* If string is part of a larger string, * this identifies beginning of larger * string, so that "^" won't match. */{ int match; regexp *regexpPtr = (regexp *) re; TclRegError((char *) NULL); match = TclRegExec(regexpPtr, string, start); if (TclGetRegError() != NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error while matching regular expression: ", TclGetRegError(), (char *) NULL); return -1; } return match;}/* *---------------------------------------------------------------------- * * Tcl_RegExpRange -- * * Returns pointers describing the range of a regular expression match, * or one of the subranges within the match. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -