📄 tclutil.c
字号:
intTcl_ScanElement(string, flagPtr) CONST char *string; /* String to convert to Tcl list element. */ int *flagPtr; /* Where to store information to guide * Tcl_ConvertCountedElement. */{ return Tcl_ScanCountedElement(string, -1, flagPtr);}/* *---------------------------------------------------------------------- * * Tcl_ScanCountedElement -- * * This procedure is a companion procedure to * Tcl_ConvertCountedElement. It scans a string to see what * needs to be done to it (e.g. add backslashes or enclosing * braces) to make the string into a valid Tcl list element. * If length is -1, then the string is scanned up to the first * null byte. * * Results: * The return value is an overestimate of the number of characters * that will be needed by Tcl_ConvertCountedElement to produce a * valid list element from string. The word at *flagPtr is * filled in with a value needed by Tcl_ConvertCountedElement * when doing the actual conversion. * * Side effects: * None. * *---------------------------------------------------------------------- */intTcl_ScanCountedElement(string, length, flagPtr) CONST char *string; /* String to convert to Tcl list element. */ int length; /* Number of bytes in string, or -1. */ int *flagPtr; /* Where to store information to guide * Tcl_ConvertElement. */{ int flags, nestingLevel; CONST char *p, *lastChar; /* * This procedure and Tcl_ConvertElement together do two things: * * 1. They produce a proper list, one that will yield back the * argument strings when evaluated or when disassembled with * Tcl_SplitList. This is the most important thing. * * 2. They try to produce legible output, which means minimizing the * use of backslashes (using braces instead). However, there are * some situations where backslashes must be used (e.g. an element * like "{abc": the leading brace will have to be backslashed. * For each element, one of three things must be done: * * (a) Use the element as-is (it doesn't contain any special * characters). This is the most desirable option. * * (b) Enclose the element in braces, but leave the contents alone. * This happens if the element contains embedded space, or if it * contains characters with special interpretation ($, [, ;, or \), * or if it starts with a brace or double-quote, or if there are * no characters in the element. * * (c) Don't enclose the element in braces, but add backslashes to * prevent special interpretation of special characters. This is a * last resort used when the argument would normally fall under case * (b) but contains unmatched braces. It also occurs if the last * character of the argument is a backslash or if the element contains * a backslash followed by newline. * * The procedure figures out how many bytes will be needed to store * the result (actually, it overestimates). It also collects information * about the element in the form of a flags word. * * Note: list elements produced by this procedure and * Tcl_ConvertCountedElement must have the property that they can be * enclosing in curly braces to make sub-lists. This means, for * example, that we must not leave unmatched curly braces in the * resulting list element. This property is necessary in order for * procedures like Tcl_DStringStartSublist to work. */ nestingLevel = 0; flags = 0; if (string == NULL) { string = ""; } if (length == -1) { length = strlen(string); } lastChar = string + length; p = string; if ((p == lastChar) || (*p == '{') || (*p == '"')) { flags |= USE_BRACES; } for ( ; p != lastChar; p++) { switch (*p) { case '{': nestingLevel++; break; case '}': nestingLevel--; if (nestingLevel < 0) { flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED; } break; case '[': case '$': case ';': case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': flags |= USE_BRACES; break; case '\\': if ((p+1 == lastChar) || (p[1] == '\n')) { flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; } else { int size; (void) Tcl_Backslash(p, &size); p += size-1; flags |= USE_BRACES; } break; } } if (nestingLevel != 0) { flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; } *flagPtr = flags; /* * Allow enough space to backslash every character plus leave * two spaces for braces. */ return 2*(p-string) + 2;}/* *---------------------------------------------------------------------- * * Tcl_ConvertElement -- * * This is a companion procedure to Tcl_ScanElement. Given * the information produced by Tcl_ScanElement, this procedure * converts a string to a list element equal to that string. * * Results: * Information is copied to *dst in the form of a list element * identical to src (i.e. if Tcl_SplitList is applied to dst it * will produce a string identical to src). The return value is * a count of the number of characters copied (not including the * terminating NULL character). * * Side effects: * None. * *---------------------------------------------------------------------- */intTcl_ConvertElement(src, dst, flags) CONST char *src; /* Source information for list element. */ char *dst; /* Place to put list-ified element. */ int flags; /* Flags produced by Tcl_ScanElement. */{ return Tcl_ConvertCountedElement(src, -1, dst, flags);}/* *---------------------------------------------------------------------- * * Tcl_ConvertCountedElement -- * * This is a companion procedure to Tcl_ScanCountedElement. Given * the information produced by Tcl_ScanCountedElement, this * procedure converts a string to a list element equal to that * string. * * Results: * Information is copied to *dst in the form of a list element * identical to src (i.e. if Tcl_SplitList is applied to dst it * will produce a string identical to src). The return value is * a count of the number of characters copied (not including the * terminating NULL character). * * Side effects: * None. * *---------------------------------------------------------------------- */intTcl_ConvertCountedElement(src, length, dst, flags) CONST char *src; /* Source information for list element. */ int length; /* Number of bytes in src, or -1. */ char *dst; /* Place to put list-ified element. */ int flags; /* Flags produced by Tcl_ScanElement. */{ char *p = dst; CONST char *lastChar; /* * See the comment block at the beginning of the Tcl_ScanElement * code for details of how this works. */ if (src && length == -1) { length = strlen(src); } if ((src == NULL) || (length == 0)) { p[0] = '{'; p[1] = '}'; p[2] = 0; return 2; } lastChar = src + length; if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) { *p = '{'; p++; for ( ; src != lastChar; src++, p++) { *p = *src; } *p = '}'; p++; } else { if (*src == '{') { /* * Can't have a leading brace unless the whole element is * enclosed in braces. Add a backslash before the brace. * Furthermore, this may destroy the balance between open * and close braces, so set BRACES_UNMATCHED. */ p[0] = '\\'; p[1] = '{'; p += 2; src++; flags |= BRACES_UNMATCHED; } for (; src != lastChar; src++) { switch (*src) { case ']': case '[': case '$': case ';': case ' ': case '\\': case '"': *p = '\\'; p++; break; case '{': case '}': /* * It may not seem necessary to backslash braces, but * it is. The reason for this is that the resulting * list element may actually be an element of a sub-list * enclosed in braces (e.g. if Tcl_DStringStartSublist * has been invoked), so there may be a brace mismatch * if the braces aren't backslashed. */ if (flags & BRACES_UNMATCHED) { *p = '\\'; p++; } break; case '\f': *p = '\\'; p++; *p = 'f'; p++; continue; case '\n': *p = '\\'; p++; *p = 'n'; p++; continue; case '\r': *p = '\\'; p++; *p = 'r'; p++; continue; case '\t': *p = '\\'; p++; *p = 't'; p++; continue; case '\v': *p = '\\'; p++; *p = 'v'; p++; continue; } *p = *src; p++; } } *p = '\0'; return p-dst;}/* *---------------------------------------------------------------------- * * Tcl_Merge -- * * Given a collection of strings, merge them together into a * single string that has proper Tcl list structured (i.e. * Tcl_SplitList may be used to retrieve strings equal to the * original elements, and Tcl_Eval will parse the string back * into its original elements). * * Results: * The return value is the address of a dynamically-allocated * string containing the merged list. * * Side effects: * None. * *---------------------------------------------------------------------- */char *Tcl_Merge(argc, argv) int argc; /* How many strings to merge. */ char **argv; /* Array of string values. */{# define LOCAL_SIZE 20 int localFlags[LOCAL_SIZE], *flagPtr; int numChars; char *result; char *dst; int i; /* * Pass 1: estimate space, gather flags. */ if (argc <= LOCAL_SIZE) { flagPtr = localFlags; } else { flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int)); } numChars = 1; for (i = 0; i < argc; i++) { numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1; } /* * Pass two: copy into the result area. */ result = (char *) ckalloc((unsigned) numChars); dst = result; for (i = 0; i < argc; i++) { numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]); dst += numChars; *dst = ' '; dst++; } if (dst == result) { *dst = 0; } else { dst[-1] = 0; } if (flagPtr != localFlags) { ckfree((char *) flagPtr); } return result;}/* *---------------------------------------------------------------------- * * Tcl_Concat -- * * Concatenate a set of strings into a single large string. * * Results: * The return value is dynamically-allocated string containing * a concatenation of all the strings in argv, with spaces between * the original argv elements. * * Side effects: * Memory is allocated for the result; the caller is responsible * for freeing the memory. * *---------------------------------------------------------------------- */char *Tcl_Concat(argc, argv) int argc; /* Number of strings to concatenate. */ char **argv; /* Array of strings to concatenate. */{ int totalSize, i; char *p; char *result; for (totalSize = 1, i = 0; i < argc; i++) { totalSize += strlen(argv[i]) + 1; } result = (char *) ckalloc((unsigned) totalSize); if (argc == 0) { *result = '\0'; return result; } for (p = result, i = 0; i < argc; i++) { char *element; 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))) { element++; } for (length = strlen(element); (length > 0) && (isspace(UCHAR(element[length-1]))) && ((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; allocSize = 0; for (i = 0; i < objc; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -