📄 tclutil.c
字号:
int length; /* * Clip white space off the front and back of the string * to generate a neater result, and ignore any empty * elements. */ element = argv[i]; while (isspace(UCHAR(*element))) { /* INTL: ISO space. */ element++; } for (length = strlen(element); (length > 0) && (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */ && ((length < 2) || (element[length-2] != '\\')); length--) { /* Null loop body. */ } if (length == 0) { continue; } memcpy((VOID *) p, (VOID *) element, (size_t) length); p += length; *p = ' '; p++; } if (p != result) { p[-1] = 0; } else { *p = 0; } return result;}/* *---------------------------------------------------------------------- * * Tcl_ConcatObj -- * * Concatenate the strings from a set of objects into a single string * object with spaces between the original strings. * * Results: * The return value is a new string object containing a concatenation * of the strings in objv. Its ref count is zero. * * Side effects: * A new object is created. * *---------------------------------------------------------------------- */Tcl_Obj *Tcl_ConcatObj(objc, objv) int objc; /* Number of objects to concatenate. */ Tcl_Obj *CONST objv[]; /* Array of objects to concatenate. */{ int allocSize, finalSize, length, elemLength, i; char *p; char *element; char *concatStr; Tcl_Obj *objPtr; /* * Check first to see if all the items are of list type. If so, * we will concat them together as lists, and return a list object. * This is only valid when the lists have no current string * representation, since we don't know what the original type was. * An original string rep may have lost some whitespace info when * converted which could be important. */ for (i = 0; i < objc; i++) { objPtr = objv[i]; if ((objPtr->typePtr != &tclListType) || (objPtr->bytes != NULL)) { break; } } if (i == objc) { Tcl_Obj **listv; int listc; objPtr = Tcl_NewListObj(0, NULL); for (i = 0; i < objc; i++) { /* * Tcl_ListObjAppendList could be used here, but this saves * us a bit of type checking (since we've already done it) * Use of INT_MAX tells us to always put the new stuff on * the end. It will be set right in Tcl_ListObjReplace. */ Tcl_ListObjGetElements(NULL, objv[i], &listc, &listv); Tcl_ListObjReplace(NULL, objPtr, INT_MAX, 0, listc, listv); } return objPtr; } allocSize = 0; for (i = 0; i < objc; i++) { objPtr = objv[i]; element = Tcl_GetStringFromObj(objPtr, &length); if ((element != NULL) && (length > 0)) { allocSize += (length + 1); } } if (allocSize == 0) { allocSize = 1; /* enough for the NULL byte at end */ } /* * Allocate storage for the concatenated result. Note that allocSize * is one more than the total number of characters, and so includes * room for the terminating NULL byte. */ concatStr = (char *) ckalloc((unsigned) allocSize); /* * Now concatenate the elements. Clip white space off the front and back * to generate a neater result, and ignore any empty elements. Also put * a null byte at the end. */ finalSize = 0; if (objc == 0) { *concatStr = '\0'; } else { p = concatStr; for (i = 0; i < objc; i++) { objPtr = objv[i]; element = Tcl_GetStringFromObj(objPtr, &elemLength); while ((elemLength > 0) && (UCHAR(*element) < 127) && isspace(UCHAR(*element))) { /* INTL: ISO C space. */ element++; elemLength--; } /* * Trim trailing white space. But, be careful not to trim * a space character if it is preceded by a backslash: in * this case it could be significant. */ while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127) && isspace(UCHAR(element[elemLength-1])) /* INTL: ISO C space. */ && ((elemLength < 2) || (element[elemLength-2] != '\\'))) { elemLength--; } if (elemLength == 0) { continue; /* nothing left of this element */ } memcpy((VOID *) p, (VOID *) element, (size_t) elemLength); p += elemLength; *p = ' '; p++; finalSize += (elemLength + 1); } if (p != concatStr) { p[-1] = 0; finalSize -= 1; /* we overwrote the final ' ' */ } else { *p = 0; } } TclNewObj(objPtr); objPtr->bytes = concatStr; objPtr->length = finalSize; return objPtr;}/* *---------------------------------------------------------------------- * * Tcl_StringMatch -- * * See if a particular string matches a particular pattern. * * Results: * The return value is 1 if string matches pattern, and * 0 otherwise. The matching operation permits the following * special characters in the pattern: *?\[] (see the manual * entry for details on what these mean). * * Side effects: * None. * *---------------------------------------------------------------------- */intTcl_StringMatch(string, pattern) CONST char *string; /* String. */ CONST char *pattern; /* Pattern, which may contain special * characters. */{ return Tcl_StringCaseMatch(string, pattern, 0);}/* *---------------------------------------------------------------------- * * Tcl_StringCaseMatch -- * * See if a particular string matches a particular pattern. * Allows case insensitivity. * * Results: * The return value is 1 if string matches pattern, and * 0 otherwise. The matching operation permits the following * special characters in the pattern: *?\[] (see the manual * entry for details on what these mean). * * Side effects: * None. * *---------------------------------------------------------------------- */intTcl_StringCaseMatch(string, pattern, nocase) CONST char *string; /* String. */ CONST char *pattern; /* Pattern, which may contain special * characters. */ int nocase; /* 0 for case sensitive, 1 for insensitive */{ int p, charLen; CONST char *pstart = pattern; Tcl_UniChar ch1, ch2; while (1) { p = *pattern; /* * See if we're at the end of both the pattern and the string. If * so, we succeeded. If we're at the end of the pattern but not at * the end of the string, we failed. */ if (p == '\0') { return (*string == '\0'); } if ((*string == '\0') && (p != '*')) { return 0; } /* * Check for a "*" as the next pattern character. It matches * any substring. We handle this by calling ourselves * recursively for each postfix of string, until either we * match or we reach the end of the string. */ if (p == '*') { /* * Skip all successive *'s in the pattern */ while (*(++pattern) == '*') {} p = *pattern; if (p == '\0') { return 1; } /* * This is a special case optimization for single-byte utf. */ if (UCHAR(*pattern) < 0x80) { ch2 = (Tcl_UniChar) (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); } else { Tcl_UtfToUniChar(pattern, &ch2); if (nocase) { ch2 = Tcl_UniCharToLower(ch2); } } while (1) { /* * Optimization for matching - cruise through the string * quickly if the next char in the pattern isn't a special * character */ if ((p != '[') && (p != '?') && (p != '\\')) { if (nocase) { while (*string) { charLen = TclUtfToUniChar(string, &ch1); if (ch2==ch1 || ch2==Tcl_UniCharToLower(ch1)) { break; } string += charLen; } } else { /* * There's no point in trying to make this code * shorter, as the number of bytes you want to * compare each time is non-constant. */ while (*string) { charLen = TclUtfToUniChar(string, &ch1); if (ch2 == ch1) { break; } string += charLen; } } } if (Tcl_StringCaseMatch(string, pattern, nocase)) { return 1; } if (*string == '\0') { return 0; } string += TclUtfToUniChar(string, &ch1); } } /* * Check for a "?" as the next pattern character. It matches * any single character. */ if (p == '?') { pattern++; string += TclUtfToUniChar(string, &ch1); continue; } /* * Check for a "[" as the next pattern character. It is followed * by a list of characters that are acceptable, or by a range * (two characters separated by "-"). */ if (p == '[') { Tcl_UniChar startChar, endChar; pattern++; if (UCHAR(*string) < 0x80) { ch1 = (Tcl_UniChar) (nocase ? tolower(UCHAR(*string)) : UCHAR(*string)); string++; } else { string += Tcl_UtfToUniChar(string, &ch1); if (nocase) { ch1 = Tcl_UniCharToLower(ch1); } } while (1) { if ((*pattern == ']') || (*pattern == '\0')) { return 0; } if (UCHAR(*pattern) < 0x80) { startChar = (Tcl_UniChar) (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); pattern++; } else { pattern += Tcl_UtfToUniChar(pattern, &startChar); if (nocase) { startChar = Tcl_UniCharToLower(startChar); } } if (*pattern == '-') { pattern++; if (*pattern == '\0') { return 0; } if (UCHAR(*pattern) < 0x80) { endChar = (Tcl_UniChar) (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); pattern++; } else { pattern += Tcl_UtfToUniChar(pattern, &endChar); if (nocase) { endChar = Tcl_UniCharToLower(endChar); } } if (((startChar <= ch1) && (ch1 <= endChar)) || ((endChar <= ch1) && (ch1 <= startChar))) { /* * Matches ranges of form [a-z] or [z-a]. */ break; } } else if (startChar == ch1) { break; } } while (*pattern != ']') { if (*pattern == '\0') { pattern = Tcl_UtfPrev(pattern, pstart); break; } pattern++; } pattern++; continue; } /* * If the next pattern character is '\', just strip off the '\' * so we do exact matching on the character that follows. */ if (p == '\\') { pattern++; if (*pattern == '\0') { return 0; } } /* * There's no special character. Just make sure that the next * bytes of each string match. */ string += TclUtfToUniChar(string, &ch1); pattern += TclUtfToUniChar(pattern, &ch2); if (nocase) { if (Tcl_UniCharToLower(ch1) != Tcl_UniCharToLower(ch2)) { return 0; } } else if (ch1 != ch2) { return 0; } }}/* *---------------------------------------------------------------------- * * Tcl_DStringInit -- * * Initializes a dynamic string, discarding any previous contents * of the string (Tcl_DStringFree should have been called already * if the dynamic string was previously in use). * * Results: * None. * * Side effects: * The dynamic string is initialized to be empty. * *---------------------------------------------------------------------- */voidTcl_DStringInit(dsPtr) Tcl_DString *dsPtr; /* Pointer to structure for dynamic string. */{ dsPtr->string = dsPtr->staticSpace; dsPtr->length = 0; dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; dsPtr->staticSpace[0] = '\0';}/* *---------------------------------------------------------------------- * * Tcl_DStringAppend -- * * Append more characters to the current value of a dynamic string. * * Results: * The return value is a pointer to the dynamic string's new value. * * Side effects: * Length bytes from string (or all of string if length is less * than zero) are added to the current value of the string. Memory * gets reallocated if needed to accomodate the string's new size. * *---------------------------------------------------------------------- */char *Tcl_DStringAppend(dsPtr, string, length) Tcl_DString *dsPtr; /* Structure describing dynamic string. */ CONST char *string; /* String to append. If length is -1 then * this must be null-terminated. */ int length; /* Number of characters from string to * append. If < 0, then append all of string, * up to null at end. */{ int newSize; char *dst; CONST char *end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -