tclcmdah.c
来自「tcl是工具命令语言」· C语言 代码 · 共 2,394 行 · 第 1/5 页
C
2,394 行
ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */{ char *format; /* Used to read characters from the format * string. */ int formatLen; /* The length of the format string */ char *endPtr; /* Points to the last char in format array */ char newFormat[43]; /* A new format specifier is generated here. */ int width; /* Field width from field specifier, or 0 if * no width given. */ int precision; /* Field precision from field specifier, or 0 * if no precision given. */ int size; /* Number of bytes needed for result of * conversion, based on type of conversion * ("e", "s", etc.), width, and precision. */ long intValue; /* Used to hold value to pass to sprintf, if * it's a one-word integer or char value */ char *ptrValue = NULL; /* Used to hold value to pass to sprintf, if * it's a one-word value. */ double doubleValue; /* Used to hold value to pass to sprintf if * it's a double value. */#ifndef TCL_WIDE_INT_IS_LONG Tcl_WideInt wideValue; /* Used to hold value to pass to sprintf if * it's a 'long long' value. */#endif /* TCL_WIDE_INT_IS_LONG */ int whichValue; /* Indicates which of intValue, ptrValue, * or doubleValue has the value to pass to * sprintf, according to the following * definitions: */# define INT_VALUE 0# define CHAR_VALUE 1# define PTR_VALUE 2# define DOUBLE_VALUE 3# define STRING_VALUE 4# define WIDE_VALUE 5# define MAX_FLOAT_SIZE 320 Tcl_Obj *resultPtr; /* Where result is stored finally. */ char staticBuf[MAX_FLOAT_SIZE + 1]; /* A static buffer to copy the format results * into */ char *dst = staticBuf; /* The buffer that sprintf writes into each * time the format processes a specifier */ int dstSize = MAX_FLOAT_SIZE; /* The size of the dst buffer */ int noPercent; /* Special case for speed: indicates there's * no field specifier, just a string to copy.*/ int objIndex; /* Index of argument to substitute next. */ int gotXpg = 0; /* Non-zero means that an XPG3 %n$-style * specifier has been seen. */ int gotSequential = 0; /* Non-zero means that a regular sequential * (non-XPG3) conversion specifier has been * seen. */ int useShort; /* Value to be printed is short (half word). */ char *end; /* Used to locate end of numerical fields. */ int stringLen = 0; /* Length of string in characters rather * than bytes. Used for %s substitution. */ int gotMinus; /* Non-zero indicates that a minus flag has * been seen in the current field. */ int gotPrecision; /* Non-zero indicates that a precision has * been set for the current field. */ int gotZero; /* Non-zero indicates that a zero flag has * been seen in the current field. */#ifndef TCL_WIDE_INT_IS_LONG int useWide; /* Value to be printed is Tcl_WideInt. */#endif /* TCL_WIDE_INT_IS_LONG */ /* * This procedure is a bit nasty. The goal is to use sprintf to * do most of the dirty work. There are several problems: * 1. this procedure can't trust its arguments. * 2. we must be able to provide a large enough result area to hold * whatever's generated. This is hard to estimate. * 3. there's no way to move the arguments from objv to the call * to sprintf in a reasonable way. This is particularly nasty * because some of the arguments may be two-word values (doubles * and wide-ints). * So, what happens here is to scan the format string one % group * at a time, making many individual calls to sprintf. */ if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "formatString ?arg arg ...?"); return TCL_ERROR; } format = Tcl_GetStringFromObj(objv[1], &formatLen); endPtr = format + formatLen; resultPtr = Tcl_NewObj(); objIndex = 2; while (format < endPtr) { register char *newPtr = newFormat; width = precision = noPercent = useShort = 0; gotZero = gotMinus = gotPrecision = 0;#ifndef TCL_WIDE_INT_IS_LONG useWide = 0;#endif /* TCL_WIDE_INT_IS_LONG */ whichValue = PTR_VALUE; /* * Get rid of any characters before the next field specifier. */ if (*format != '%') { ptrValue = format; while ((*format != '%') && (format < endPtr)) { format++; } size = format - ptrValue; noPercent = 1; goto doField; } if (format[1] == '%') { ptrValue = format; size = 1; noPercent = 1; format += 2; goto doField; } /* * Parse off a field specifier, compute how many characters * will be needed to store the result, and substitute for * "*" size specifiers. */ *newPtr = '%'; newPtr++; format++; if (isdigit(UCHAR(*format))) { /* INTL: Tcl source. */ int tmp; /* * Check for an XPG3-style %n$ specification. Note: there * must not be a mixture of XPG3 specs and non-XPG3 specs * in the same format string. */ tmp = strtoul(format, &end, 10); /* INTL: "C" locale. */ if (*end != '$') { goto notXpg; } format = end+1; gotXpg = 1; if (gotSequential) { goto mixedXPG; } objIndex = tmp+1; if ((objIndex < 2) || (objIndex >= objc)) { goto badIndex; } goto xpgCheckDone; } notXpg: gotSequential = 1; if (gotXpg) { goto mixedXPG; } xpgCheckDone: while ((*format == '-') || (*format == '#') || (*format == '0') || (*format == ' ') || (*format == '+')) { if (*format == '-') { gotMinus = 1; } if (*format == '0') { /* * This will be handled by sprintf for numbers, but we * need to do the char/string ones ourselves */ gotZero = 1; } *newPtr = *format; newPtr++; format++; } if (isdigit(UCHAR(*format))) { /* INTL: Tcl source. */ width = strtoul(format, &end, 10); /* INTL: Tcl source. */ format = end; } else if (*format == '*') { if (objIndex >= objc) { goto badIndex; } if (Tcl_GetIntFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &width) != TCL_OK) { goto fmtError; } if (width < 0) { width = -width; *newPtr = '-'; gotMinus = 1; newPtr++; } objIndex++; format++; } if (width > 100000) { /* * Don't allow arbitrarily large widths: could cause core * dump when we try to allocate a zillion bytes of memory * below. */ width = 100000; } else if (width < 0) { width = 0; } if (width != 0) { TclFormatInt(newPtr, width); /* INTL: printf format. */ while (*newPtr != 0) { newPtr++; } } if (*format == '.') { *newPtr = '.'; newPtr++; format++; gotPrecision = 1; } if (isdigit(UCHAR(*format))) { /* INTL: Tcl source. */ precision = strtoul(format, &end, 10); /* INTL: "C" locale. */ format = end; } else if (*format == '*') { if (objIndex >= objc) { goto badIndex; } if (Tcl_GetIntFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &precision) != TCL_OK) { goto fmtError; } objIndex++; format++; } if (gotPrecision) { TclFormatInt(newPtr, precision); /* INTL: printf format. */ while (*newPtr != 0) { newPtr++; } } if (*format == 'l') {#ifndef TCL_WIDE_INT_IS_LONG useWide = 1; strcpy(newPtr, TCL_LL_MODIFIER); newPtr += TCL_LL_MODIFIER_SIZE;#endif /* TCL_WIDE_INT_IS_LONG */ format++; } else if (*format == 'h') { useShort = 1; *newPtr = 'h'; newPtr++; format++; } *newPtr = *format; newPtr++; *newPtr = 0; if (objIndex >= objc) { goto badIndex; } switch (*format) { case 'i': newPtr[-1] = 'd'; case 'd': case 'o': case 'u': case 'x': case 'X':#ifndef TCL_WIDE_INT_IS_LONG if (useWide) { if (Tcl_GetWideIntFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &wideValue) != TCL_OK) { goto fmtError; } whichValue = WIDE_VALUE; size = 40 + precision; break; }#endif /* TCL_WIDE_INT_IS_LONG */ if (Tcl_GetLongFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &intValue) != TCL_OK) { goto fmtError; }#if (LONG_MAX > INT_MAX) /* * Add the 'l' for long format type because we are on * an LP64 archtecture and we are really going to pass * a long argument to sprintf. */ newPtr++; *newPtr = 0; newPtr[-1] = newPtr[-2]; newPtr[-2] = 'l';#endif /* LONG_MAX > INT_MAX */ whichValue = INT_VALUE; size = 40 + precision; break; case 's': /* * Compute the length of the string in characters and add * any additional space required by the field width. All of * the extra characters will be spaces, so one byte per * character is adequate. */ whichValue = STRING_VALUE; ptrValue = Tcl_GetStringFromObj(objv[objIndex], &size); stringLen = Tcl_NumUtfChars(ptrValue, size); if (gotPrecision && (precision < stringLen)) { stringLen = precision; } size = Tcl_UtfAtIndex(ptrValue, stringLen) - ptrValue; if (width > stringLen) { size += (width - stringLen); } break; case 'c': if (Tcl_GetLongFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &intValue) != TCL_OK) { goto fmtError; } whichValue = CHAR_VALUE; size = width + TCL_UTF_MAX; break; case 'e': case 'E': case 'f': case 'g': case 'G': if (Tcl_GetDoubleFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &doubleValue) != TCL_OK) { goto fmtError; } whichValue = DOUBLE_VALUE; size = MAX_FLOAT_SIZE; if (precision > 10) { size += precision; } break; case 0: Tcl_SetResult(interp, "format string ended in middle of field specifier", TCL_STATIC); goto fmtError; default: { char buf[40]; sprintf(buf, "bad field specifier \"%c\"", *format); Tcl_SetResult(interp, buf, TCL_VOLATILE); goto fmtError; } } objIndex++; format++; /* * Make sure that there's enough space to hold the formatted * result, then format it. */ doField: if (width > size) { size = width; } if (noPercent) { Tcl_AppendToObj(resultPtr, ptrValue, size); } else { if (size > dstSize) { if (dst != staticBuf) { ckfree(dst); } dst = (char *) ckalloc((unsigned) (size + 1)); dstSize = size; } switch (whichValue) { case DOUBLE_VALUE: { sprintf(dst, newFormat, doubleValue); /* INTL: user locale. */ break; }#ifndef TCL_WIDE_INT_IS_LONG case WIDE_VALUE: { sprintf(dst, newFormat, wideValue); break; }#endif /* TCL_WIDE_INT_IS_LONG */ case INT_VALUE: { if (useShort) { sprintf(dst, newFormat, (short) intValue); } else { sprintf(dst, newFormat, intValue); } break; } case CHAR_VALUE: { char *ptr; char padChar = (gotZero ? '0' : ' '); ptr = dst; if (!gotMinus) { for ( ; --width > 0; ptr++) { *ptr = padChar; } } ptr += Tcl_UniCharToUtf(intValue, ptr); for ( ; --width > 0; ptr++) { *ptr = padChar; } *ptr = '\0'; break; } case STRING_VALUE: { char *ptr; char padChar = (gotZero ? '0' : ' '); int pad; ptr = dst; if (width > stringLen) { pad = width - stringLen; } else { pad = 0; } if (!gotMinus) { while (pad > 0) { *ptr++ = padChar; pad--; } } size = Tcl_UtfAtIndex(ptrValue, stringLen) - ptrValue; if (size) { memcpy(ptr, ptrValue, (size_t) size); ptr += size; } while (pad > 0) { *ptr++ = padChar; pad--; } *ptr = '\0'; break; } default: { sprintf(dst, newFormat, ptrValue); break; } } Tcl_AppendToObj(resultPtr, dst, -1); } } Tcl_SetObjResult(interp, resultPtr); if(dst != staticBuf) { ckfree(dst); } return TCL_OK; mixedXPG: Tcl_SetResult(interp, "cannot mix \"%\" and \"%n$\" conversion specifiers", TCL_STATIC); goto fmtError; badIndex: if (gotXpg) { Tcl_SetResult(interp, "\"%n$\" argument index out of range", TCL_STATIC); } else { Tcl_SetResult(interp, "not enough arguments for all format specifiers", TCL_STATIC); } fmtError: if(dst != staticBuf) { ckfree(dst); } Tcl_DecrRefCount(resultPtr); return TCL_ERROR;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?