#define ISDIGIT(s) (s) == DIGIT_ZERO || \
(s) == DIGIT_ONE || \
(s) == DIGIT_TWO || \
(s) == DIGIT_THREE || \
(s) == DIGIT_FOUR || \
(s) == DIGIT_FIVE || \
(s) == DIGIT_SIX || \
(s) == DIGIT_SEVEN || \
(s) == DIGIT_EIGHT || \
(s) == DIGIT_NINE
#define ISMOD(s) (s) == MOD_H || \
(s) == MOD_LOWERL || \
(s) == MOD_L
/** * Struct encapsulating a single uscanf format specification.
*/ typedefstruct u_scanf_spec_info {
int32_t fWidth; /* Width */
char16_t fSpec; /* Format specification */
char16_t fPadChar; /* Padding character */
UBool fSkipArg; /* true if arg should be skipped */
UBool fIsLongDouble; /* L flag */
UBool fIsShort; /* h flag */
UBool fIsLong; /* l flag */
UBool fIsLongLong; /* ll flag */
UBool fIsString; /* true if this is a NUL-terminated string. */
} u_scanf_spec_info;
/** * Struct encapsulating a single u_scanf format specification.
*/ typedefstruct u_scanf_spec {
u_scanf_spec_info fInfo; /* Information on this spec */
int32_t fArgPos; /* Position of data in arg list */
} u_scanf_spec;
/** * Parse a single u_scanf format specifier in Unicode. * @param fmt A pointer to a '%' character in a u_scanf format specification. * @param spec A pointer to a <TT>u_scanf_spec</TT> to receive the parsed * format specifier. * @return The number of characters contained in this specifier.
*/ static int32_t
u_scanf_parse_spec (const char16_t *fmt,
u_scanf_spec *spec)
{ const char16_t *s = fmt; const char16_t *backup;
u_scanf_spec_info *info = &(spec->fInfo);
/* initialize spec to default values */
spec->fArgPos = -1;
/* Get any modifiers */ if(ISMOD(*s)) { switch(*s++) {
/* short */ case MOD_H:
info->fIsShort = true; break;
/* long or long long */ case MOD_LOWERL: if(*s == MOD_LOWERL) {
info->fIsLongLong = true; /* skip over the next 'l' */
s++;
} else
info->fIsLong = true; break;
/* long double */ case MOD_L:
info->fIsLongDouble = true; break;
}
}
/* finally, get the specifier letter */
info->fSpec = *s++;
/* return # of characters in this specifier */ returnstatic_cast<int32_t>(s - fmt);
}
#define UP_PERCENT 0x0025
/* ANSI style formatting */ /* Use US-ASCII characters only for formatting */
/* % */ #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_scanf_simple_percent_handler} /* s */ #define UFMT_STRING {ufmt_string, u_scanf_string_handler} /* c */ #define UFMT_CHAR {ufmt_string, u_scanf_char_handler} /* d, i */ #define UFMT_INT {ufmt_int, u_scanf_integer_handler} /* u */ #define UFMT_UINT {ufmt_int, u_scanf_uinteger_handler} /* o */ #define UFMT_OCTAL {ufmt_int, u_scanf_octal_handler} /* x, X */ #define UFMT_HEX {ufmt_int, u_scanf_hex_handler} /* f */ #define UFMT_DOUBLE {ufmt_double, u_scanf_double_handler} /* e, E */ #define UFMT_SCIENTIFIC {ufmt_double, u_scanf_scientific_handler} /* g, G */ #define UFMT_SCIDBL {ufmt_double, u_scanf_scidbl_handler} /* n */ #define UFMT_COUNT {ufmt_count, u_scanf_count_handler} /* [ */ #define UFMT_SCANSET {ufmt_string, u_scanf_scanset_handler}
/* non-ANSI extensions */ /* Use US-ASCII characters only for formatting */
/* p */ #define UFMT_POINTER {ufmt_pointer, u_scanf_pointer_handler} /* V */ #define UFMT_SPELLOUT {ufmt_double, u_scanf_spellout_handler} /* P */ #define UFMT_PERCENT {ufmt_double, u_scanf_percent_handler} /* C K is old format */ #define UFMT_UCHAR {ufmt_uchar, u_scanf_uchar_handler} /* S U is old format */ #define UFMT_USTRING {ufmt_ustring, u_scanf_ustring_handler}
#define UFMT_EMPTY {ufmt_empty, nullptr}
/** * A u_scanf handler function. * A u_scanf handler is responsible for handling a single u_scanf * format specification, for example 'd' or 's'. * @param stream The UFILE to which to write output. * @param info A pointer to a <TT>u_scanf_spec_info</TT> struct containing * information on the format specification. * @param args A pointer to the argument data * @param fmt A pointer to the first character in the format string * following the spec. * @param fmtConsumed On output, set to the number of characters consumed * in <TT>fmt</TT>. Do nothing, if the argument isn't variable width. * @param argConverted The number of arguments converted and assigned, or -1 if an * error occurred. * @return The number of code points consumed during reading.
*/ typedef int32_t (*u_scanf_handler) (UFILE *stream,
u_scanf_spec_info *info,
ufmt_args *args, const char16_t *fmt,
int32_t *fmtConsumed,
int32_t *argConverted);
/* skip all leading ws in the input */ while (((isNotEOF = ufile_getch(input, &c)) == static_cast<UBool>(true)) && (c == pad || u_isWhitespace(c)))
{
count++;
}
/* put the final character back on the input */ if(isNotEOF)
u_fungetc(c, input);
return count;
}
/* TODO: Is always skipping the prefix symbol as a positive sign a good idea in all locales? */ static int32_t
u_scanf_skip_leading_positive_sign(UFILE *input,
UNumberFormat *format,
UErrorCode *status)
{
char16_t c;
int32_t count = 0;
UBool isNotEOF;
char16_t plusSymbol[USCANF_SYMBOL_BUFFER_SIZE];
int32_t symbolLen;
UErrorCode localStatus = U_ZERO_ERROR;
if (U_SUCCESS(*status)) {
symbolLen = unum_getSymbol(format,
UNUM_PLUS_SIGN_SYMBOL,
plusSymbol,
UPRV_LENGTHOF(plusSymbol),
&localStatus);
if (U_SUCCESS(localStatus)) { /* skip all leading ws in the input */ while (((isNotEOF = ufile_getch(input, &c)) == static_cast<UBool>(true)) && (count < symbolLen && c == plusSymbol[count]))
{
count++;
}
/* put the final character back on the input */ if(isNotEOF) {
u_fungetc(c, input);
}
}
}
/* in the special case of count, the u_scanf_spec_info's width */ /* will contain the # of items converted thus far */ if (!info->fSkipArg) { if (info->fIsShort)
*static_cast<int16_t*>(args[0].ptrValue) = static_cast<int16_t>(UINT16_MAX & info->fWidth); elseif (info->fIsLongLong)
*static_cast<int64_t*>(args[0].ptrValue) = info->fWidth; else
*static_cast<int32_t*>(args[0].ptrValue) = static_cast<int32_t>(UINT32_MAX & info->fWidth);
}
*argConverted = 0;
/* skip all ws in the input */
skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
/* fill the input's internal buffer */
ufile_fill_uchar_buffer(input);
/* determine the size of the input's buffer */
len = static_cast<int32_t>(input->str.fLimit - input->str.fPos);
/* truncate to the width, if specified */ if(info->fWidth != -1)
len = ufmt_min(len, info->fWidth);
/* get the formatter */
format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
/* handle error */ if (format == nullptr) return 0;
/* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
/* parse the number */
num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
if (!info->fSkipArg) { if (info->fIsLong)
*static_cast<double*>(args[0].ptrValue) = num; elseif (info->fIsLongDouble)
*static_cast<longdouble*>(args[0].ptrValue) = num; else
*static_cast<float*>(args[0].ptrValue) = static_cast<float>(num);
}
/* mask off any necessary bits */ /* if(! info->fIsLong_double)
num &= DBL_MAX;*/
/* update the input's position to reflect consumed data */
input->str.fPos += parsePos;
/* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
/* parse the number */
num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
if (!info->fSkipArg) { if (info->fIsLong)
*static_cast<double*>(args[0].ptrValue) = num; elseif (info->fIsLongDouble)
*static_cast<longdouble*>(args[0].ptrValue) = num; else
*static_cast<float*>(args[0].ptrValue) = static_cast<float>(num);
}
/* mask off any necessary bits */ /* if(! info->fIsLong_double)
num &= DBL_MAX;*/
/* update the input's position to reflect consumed data */
input->str.fPos += parsePos;
/* since we can't determine by scanning the characters whether */ /* a number was formatted in the 'f' or 'g' styles, parse the */ /* string with both formatters, and assume whichever one */ /* parsed the most is the correct formatter to use */
/* skip all ws in the input */
skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
/* fill the input's internal buffer */
ufile_fill_uchar_buffer(input);
/* determine the size of the input's buffer */
len = static_cast<int32_t>(input->str.fLimit - input->str.fPos);
/* truncate to the width, if specified */ if(info->fWidth != -1)
len = ufmt_min(len, info->fWidth);
/* get the formatters */
scientificFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
genericFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
/* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
skipped += u_scanf_skip_leading_positive_sign(input, genericFormat, &genericStatus);
/* determine which parse made it farther */ if(scientificParsePos > genericParsePos) { /* stash the result in num */
num = scientificResult; /* update the input's position to reflect consumed data */
parsePos += scientificParsePos;
} else { /* stash the result in num */
num = genericResult; /* update the input's position to reflect consumed data */
parsePos += genericParsePos;
}
input->str.fPos += parsePos;
if (!info->fSkipArg) { if (info->fIsLong)
*static_cast<double*>(args[0].ptrValue) = num; elseif (info->fIsLongDouble)
*static_cast<longdouble*>(args[0].ptrValue) = num; else
*static_cast<float*>(args[0].ptrValue) = static_cast<float>(num);
}
/* mask off any necessary bits */ /* if(! info->fIsLong_double)
num &= DBL_MAX;*/
/* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
skipped += u_scanf_skip_leading_positive_sign(input, localFormat, &status);
/* parse the number */
result = unum_parseInt64(localFormat, input->str.fPos, len, &parsePos, &status);
/* mask off any necessary bits */ if (!info->fSkipArg) { if (info->fIsShort)
*static_cast<int16_t*>(num) = static_cast<int16_t>(UINT16_MAX & result); elseif (info->fIsLongLong)
*static_cast<int64_t*>(num) = result; else
*static_cast<int32_t*>(num) = static_cast<int32_t>(UINT32_MAX & result);
}
/* update the input's position to reflect consumed data */
input->str.fPos += parsePos;
if (!info->fSkipArg) { /* put the character from the input onto the target */
source = &c; /* Since we do this one character at a time, do it this way. */ if (info->fWidth > 0) {
limit = alias + info->fWidth - count;
} else {
limit = alias + ucnv_getMaxCharSize(conv);
}
/* convert the character to the default codepage */
ucnv_fromUnicode(conv, &alias, limit, &source, source + 1,
nullptr, true, &status);
/* put the final character we read back on the input */ if (!info->fSkipArg) { if ((info->fWidth == -1 || count < info->fWidth) && isNotEOF)
u_fungetc(c, input);
/* add the terminator */ if (info->fIsString) {
*alias = 0x00;
}
}
/* put the character from the input onto the target */ if (!info->fSkipArg) {
*alias++ = c;
}
/* increment the count */
++count;
}
/* put the final character we read back on the input */ if (!info->fSkipArg) { if((info->fWidth == -1 || count < info->fWidth) && isNotEOF) {
u_fungetc(c, input);
}
/* add the terminator */ if (info->fIsString) {
*alias = 0x0000;
}
}
/* skip all ws in the input */
skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
/* fill the input's internal buffer */
ufile_fill_uchar_buffer(input);
/* determine the size of the input's buffer */
len = static_cast<int32_t>(input->str.fLimit - input->str.fPos);
/* truncate to the width, if specified */ if(info->fWidth != -1)
len = ufmt_min(len, info->fWidth);
/* get the formatter */
format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SPELLOUT);
/* handle error */ if (format == nullptr) return 0;
/* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */ /* This is not applicable to RBNF. */ /*skipped += u_scanf_skip_leading_positive_sign(input, format, &status);*/
/* parse the number */
num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
if (!info->fSkipArg) {
*static_cast<double*>(args[0].ptrValue) = num;
}
/* mask off any necessary bits */ /* if(! info->fIsLong_double)
num &= DBL_MAX;*/
/* update the input's position to reflect consumed data */
input->str.fPos += parsePos;
/* Create an empty set */
scanset = uset_open(0, -1);
/* Back up one to get the [ */
fmt--;
/* truncate to the width, if specified and alias the target */ if(info->fWidth >= 0) {
chLeft = info->fWidth;
}
/* parse the scanset from the fmt string */
*fmtConsumed = uset_applyPattern(scanset, fmt, -1, 0, &status);
/* verify that the parse was successful */ if (U_SUCCESS(status)) {
c=0;
/* grab characters one at a time and make sure they are in the scanset */ while(chLeft > 0) { if (((isNotEOF = ufile_getch32(input, &c)) == static_cast<UBool>(true)) && uset_contains(scanset, c)) {
readCharacter = true; if (!info->fSkipArg) {
int32_t idx = 0;
UBool isError = false;
U16_APPEND(alias, idx, chLeft, c, isError); if (isError) { break;
}
alias += idx;
}
chLeft -= (1 + U_IS_SUPPLEMENTARY(c));
} else { /* if the character's not in the scanset, break out */ break;
}
}
/* put the final character we read back on the input */ if(isNotEOF && chLeft > 0) {
u_fungetc(c, input);
}
}
uset_close(scanset);
/* if we didn't match at least 1 character, fail */ if(!readCharacter) return -1; /* otherwise, add the terminator */ elseif (!info->fSkipArg) {
*alias = 0x00;
}
/* Use US-ASCII characters only for formatting. Most codepages have characters 20-7F from Unicode. Using any other codepage specific characters will make it very difficult to format the string on
non-Unicode machines */ staticconst u_scanf_info g_u_scanf_infos[USCANF_NUM_FMT_HANDLERS] = { /* 0x20 */
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY,
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
/* match any characters up to the next '%' */ while(*alias != UP_PERCENT && *alias != 0x0000 && u_fgetc(f) == *alias) {
alias++;
}
/* if we aren't at a '%', or if we're at end of string, break*/ if(*alias != UP_PERCENT || *alias == 0x0000) break;
/* parse the specifier */
count = u_scanf_parse_spec(alias, &spec);
/* update the pointer in pattern */
alias += count;
handlerNum = (uint16_t)(spec.fInfo.fSpec - USCANF_BASE_FMT_HANDLERS); if (handlerNum < USCANF_NUM_FMT_HANDLERS) { /* skip the argument, if necessary */ /* query the info function for argument information */
info = g_u_scanf_infos[ handlerNum ].info; if (info != ufmt_count && u_feof(f)) { break;
} elseif(spec.fInfo.fSkipArg) {
args.ptrValue = nullptr;
} else { switch(info) { case ufmt_count: /* set the spec's width to the # of items converted */
spec.fInfo.fWidth = cpConsumed;
U_FALLTHROUGH; case ufmt_char: case ufmt_uchar: case ufmt_int: case ufmt_string: case ufmt_ustring: case ufmt_pointer: case ufmt_float: case ufmt_double:
args.ptrValue = va_arg(ap, void*); break;
/* call the handler function */
handler = g_u_scanf_infos[ handlerNum ].handler; if (handler != nullptr) { /* reset count to 1 so that += for alias works. */
count = 1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.