📄 trio.c
字号:
/************************************************************************* * Internal variables */#if defined(PLATFORM_UNIX)extern int errno;#endifstatic const char null[] = "(nil)";#if defined(USE_LOCALE)static struct lconv *internalLocaleValues = NULL;#endif/* * UNIX98 says "in a locale where the radix character is not defined, * the radix character defaults to a period (.)" */static char internalDecimalPoint[MAX_LOCALE_SEPARATOR_LENGTH] = ".";static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH] = ",";static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };static const char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";static const char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";static userdef_T *internalUserDef = NULL;static BOOLEAN_T internalDigitsUnconverted = TRUE;static int internalDigitArray[128];/************************************************************************* * trio_strerror [public] */const char *trio_strerror(int errorcode){ /* Textual versions of the error codes */ switch (TRIO_ERROR_CODE(errorcode)) { case TRIO_EOF: return "End of file"; case TRIO_EINVAL: return "Invalid argument"; case TRIO_ETOOMANY: return "Too many arguments"; case TRIO_EDBLREF: return "Double reference"; case TRIO_EGAP: return "Reference gap"; case TRIO_ENOMEM: return "Out of memory"; case TRIO_ERANGE: return "Invalid range"; default: return "Unknown"; }}/************************************************************************* * TrioIsQualifier [private] * * Description: * Remember to add all new qualifiers to this function. * QUALIFIER_POSITION must not be added. */static BOOLEAN_TTrioIsQualifier(const char ch){ /* QUALIFIER_POSITION is not included */ switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case QUALIFIER_PLUS: case QUALIFIER_MINUS: case QUALIFIER_SPACE: case QUALIFIER_DOT: case QUALIFIER_STAR: case QUALIFIER_ALTERNATIVE: case QUALIFIER_SHORT: case QUALIFIER_LONG: case QUALIFIER_LONG_UPPER: case QUALIFIER_CIRCUMFLEX:#if defined(QUALIFIER_SIZE_T) case QUALIFIER_SIZE_T:#endif#if defined(QUALIFIER_PTRDIFF_T) case QUALIFIER_PTRDIFF_T:#endif#if defined(QUALIFIER_INTMAX_T) case QUALIFIER_INTMAX_T:#endif#if defined(QUALIFIER_QUAD) case QUALIFIER_QUAD:#endif#if defined(QUALIFIER_SIZE_T_UPPER) case QUALIFIER_SIZE_T_UPPER:#endif#if defined(QUALIFIER_WIDECHAR) case QUALIFIER_WIDECHAR:#endif#if defined(QUALIFIER_QUOTE) case QUALIFIER_QUOTE:#endif#if defined(QUALIFIER_STICKY) case QUALIFIER_STICKY:#endif#if defined(QUALIFIER_VARSIZE) case QUALIFIER_VARSIZE:#endif#if defined(QUALIFIER_PARAM) case QUALIFIER_PARAM:#endif return TRUE; default: return FALSE; }}/************************************************************************* * TrioIsNan [private] */static intTrioIsNan(double number){#ifdef isnan /* C99 defines isnan() as a macro */ return isnan(number);#else double integral, fraction; return (/* NaN is the only number which does not compare to itself */ (number != number) || /* Fallback solution if NaN compares to NaN */ ((number != 0.0) && (fraction = modf(number, &integral), integral == fraction)));#endif}/************************************************************************* * TrioIsInfinite [private] */static intTrioIsInfinite(double number){#ifdef isinf /* C99 defines isinf() as a macro */ return isinf(number);#else return ((number == HUGE_VAL) ? 1 : ((number == -HUGE_VAL) ? -1 : 0));#endif}/************************************************************************* * TrioSetLocale [private] */#if defined(USE_LOCALE)static voidTrioSetLocale(void){ internalLocaleValues = (struct lconv *)localeconv(); if (StrLength(internalLocaleValues->decimal_point) > 0) { StrCopyMax(internalDecimalPoint, sizeof(internalDecimalPoint), internalLocaleValues->decimal_point); } if (StrLength(internalLocaleValues->thousands_sep) > 0) { StrCopyMax(internalThousandSeparator, sizeof(internalThousandSeparator), internalLocaleValues->thousands_sep); } if (StrLength(internalLocaleValues->grouping) > 0) { StrCopyMax(internalGrouping, sizeof(internalGrouping), internalLocaleValues->grouping); }}#endif /* defined(USE_LOCALE) *//************************************************************************* * TrioGetPosition [private] * * Get the %n$ position. */static intTrioGetPosition(const char *format, int *indexPointer){ char *tmpformat; int number = 0; int index = *indexPointer; number = (int)StrToLong(&format[index], &tmpformat, BASE_DECIMAL); index = (int)(tmpformat - format); if ((number != 0) && (QUALIFIER_POSITION == format[index++])) { *indexPointer = index; /* * number is decreased by 1, because n$ starts from 1, whereas * the array it is indexing starts from 0. */ return number - 1; } return NO_POSITION;}/************************************************************************* * TrioFindNamespace [private] * * Find registered user-defined specifier. * The prev argument is used for optimisation only. */static userdef_T *TrioFindNamespace(const char *name, userdef_T **prev){ userdef_T *def; for (def = internalUserDef; def; def = def->next) { /* Case-sensitive string comparison */ if (StrEqualCase(def->name, name)) return def; if (prev) *prev = def; } return def;}/************************************************************************* * TrioPreprocess [private] * * Description: * Parse the format string */static intTrioPreprocess(int type, const char *format, parameter_T *parameters, va_list arglist, void **argarray){#if defined(TRIO_ERRORS) /* Count the number of times a parameter is referenced */ unsigned short usedEntries[MAX_PARAMETERS];#endif /* Parameter counters */ int parameterPosition; int currentParam; int maxParam = -1; /* Utility variables */ unsigned long flags; int width; int precision; int varsize; int base; int index; /* Index into formatting string */ int dots; /* Count number of dots in modifier part */ BOOLEAN_T positional; /* Does the specifier have a positional? */ BOOLEAN_T got_sticky = FALSE; /* Are there any sticky modifiers at all? */ /* * indices specifies the order in which the parameters must be * read from the va_args (this is necessary to handle positionals) */ int indices[MAX_PARAMETERS]; int pos = 0; /* Various variables */ char ch; int charlen; int i = -1; int num; char *tmpformat;#if defined(TRIO_ERRORS) /* * The 'parameters' array is not initialized, but we need to * know which entries we have used. */ memset(usedEntries, 0, sizeof(usedEntries));#endif index = 0; parameterPosition = 0;#if defined(USE_MULTIBYTE) mblen(NULL, 0);#endif while (format[index]) {#if defined(USE_MULTIBYTE) if (! isascii(format[index])) { /* * Multibyte characters cannot be legal specifiers or * modifiers, so we skip over them. */ charlen = mblen(&format[index], MB_LEN_MAX); index += (charlen > 0) ? charlen : 1; continue; /* while */ }#endif /* defined(USE_MULTIBYTE) */ if (CHAR_IDENTIFIER == format[index++]) { if (CHAR_IDENTIFIER == format[index]) { index++; continue; /* while */ } flags = FLAGS_NEW; dots = 0; currentParam = TrioGetPosition(format, &index); positional = (NO_POSITION != currentParam); if (!positional) { /* We have no positional, get the next counter */ currentParam = parameterPosition; } if(currentParam >= MAX_PARAMETERS) { /* Bail out completely to make the error more obvious */ return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index); } if (currentParam > maxParam) maxParam = currentParam; /* Default values */ width = NO_WIDTH; precision = NO_PRECISION; base = NO_BASE; varsize = NO_SIZE; while (TrioIsQualifier(format[index])) { ch = format[index++]; switch (ch) { case QUALIFIER_SPACE: flags |= FLAGS_SPACE; break; case QUALIFIER_PLUS: flags |= FLAGS_SHOWSIGN; break; case QUALIFIER_MINUS: flags |= FLAGS_LEFTADJUST; flags &= ~FLAGS_NILPADDING; break; case QUALIFIER_ALTERNATIVE: flags |= FLAGS_ALTERNATIVE; break; case QUALIFIER_DOT: if (dots == 0) /* Precision */ { dots++; /* Skip if no precision */ if (QUALIFIER_DOT == format[index]) break; /* After the first dot we have the precision */ flags |= FLAGS_PRECISION; if ((QUALIFIER_STAR == format[index]) || (QUALIFIER_PARAM == format[index])) { index++; flags |= FLAGS_PRECISION_PARAMETER; precision = TrioGetPosition(format, &index); if (precision == NO_POSITION) { parameterPosition++; if (positional) precision = parameterPosition; else { precision = currentParam; currentParam = precision + 1; } } else { if (! positional) currentParam = precision + 1; if (width > maxParam) maxParam = precision; } if (currentParam > maxParam) maxParam = currentParam; } else { precision = StrToLong(&format[index], &tmpformat, BASE_DECIMAL); index = (int)(tmpformat - format); } } else if (dots == 1) /* Base */ { dots++; /* After the second dot we have the base */ flags |= FLAGS_BASE; if ((QUALIFIER_STAR == format[index]) || (QUALIFIER_PARAM == format[index])) { index++; flags |= FLAGS_BASE_PARAMETER; base = TrioGetPosition(format, &index); if (base == NO_POSITION) { parameterPosition++; if (positional) base = parameterPosition; else { base = currentParam; currentParam = base + 1; } } else { if (! positional) currentParam = base + 1; if (base > maxParam) maxParam = base; } if (currentParam > maxParam) maxParam = currentParam; } else { base = StrToLong(&format[index], &tmpformat, BASE_DECIMAL); if (base > MAX_BASE) return TRIO_ERROR_RETURN(TRIO_EINVAL, index); index = (int)(tmpformat - format); } } else { return TRIO_ERROR_RETURN(TRIO_EINVAL, index); } break; /* QUALIFIER_DOT */ case QUALIFIER_PARAM: type = TYPE_PRINT; /* FALLTHROUGH */ case QUALIFIER_STAR: /* This has different meanings for print and scan */ if (TYPE_PRINT == type) { /* Read with from parameter */ flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER); width = TrioGetPosition(format, &index); if (width == NO_POSITION) { parameterPosition++; if (positional) width = parameterPosition; else { width = currentParam; currentParam = width + 1; } } else { if (! positional) currentParam = width + 1; if (width > maxParam) maxParam = width; } if (currentParam > maxParam) maxParam = currentParam; } else { /* Scan, but do not store result */ flags |= FLAGS_IGNORE; } break; /* QUALIFIER_STAR */ case '0': if (! (flags & FLAGS_LEFTADJUST)) flags |= FLAGS_NILPADDING; /* FALLTHROUGH */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': flags |= FLAGS_WIDTH; /* &format[index - 1] is used to "rewind" the read * character from format */ width = StrToLong(&format[index - 1], &tmpformat, BASE_DECIMAL); index = (int)(tmpformat - format); break; case QUALIFIER_SHORT: if (flags & FLAGS_SHORTSHORT) return TRIO_ERROR_RETURN(TRIO_EINVAL, index); else if (flags & FLAGS_SHORT) flags |= FLAGS_SHORTSHORT; else flags |= FLAGS_SHORT; break; case QUALIFIER_LONG: if (flags & FLAGS_QUAD) return TRIO_ERROR_RETURN(TRIO_EINVAL, index); else if (flags & FLAGS_LONG) flags |= FLAGS_QUAD; else flags |= FLAGS_LONG; break; case QUALIFIER_LONG_UPPER: flags |= FLAGS_LONGDOUBLE; break;#if defined(QUALIFIER_SIZE_T) case QUALIFIER_SIZE_T: flags |= FLAGS_SIZE_T; /* Modify flags for later truncation of number */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -