//===-- String type specifier converters for scanf --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "src/stdio/scanf_core/string_converter.h" #include "src/__support/CPP/limits.h" #include "src/__support/ctype_utils.h" #include "src/__support/macros/config.h" #include "src/stdio/scanf_core/core_structs.h" #include "src/stdio/scanf_core/reader.h" #include namespace LIBC_NAMESPACE_DECL { namespace scanf_core { int convert_string(Reader *reader, const FormatSection &to_conv) { // %s "Matches a sequence of non-white-space characters" // %c "Matches a sequence of characters of exactly the number specified by the // field width (1 if no field width is present in the directive)" // %[ "Matches a nonempty sequence of characters from a set of expected // characters (the scanset)." size_t max_width = 0; if (to_conv.max_width > 0) { max_width = to_conv.max_width; } else { if (to_conv.conv_name == 'c') { max_width = 1; } else { max_width = cpp::numeric_limits::max(); } } char *output = reinterpret_cast(to_conv.output_ptr); char cur_char = reader->getc(); size_t i = 0; for (; i < max_width && cur_char != '\0'; ++i) { // If this is %s and we've hit a space, or if this is %[] and we've found // something not in the scanset. if ((to_conv.conv_name == 's' && internal::isspace(cur_char)) || (to_conv.conv_name == '[' && !to_conv.scan_set.test(cur_char))) { break; } // if the NO_WRITE flag is not set, write to the output. if ((to_conv.flags & NO_WRITE) == 0) output[i] = cur_char; cur_char = reader->getc(); } // We always read one more character than will be used, so we have to put the // last one back. reader->ungetc(cur_char); // If this is %s or %[] if (to_conv.conv_name != 'c' && (to_conv.flags & NO_WRITE) == 0) { // Always null terminate the string. This may cause a write to the // (max_width + 1) byte, which is correct. The max width describes the max // number of characters read from the input string, and doesn't necessarily // correspond to the output. output[i] = '\0'; } if (i == 0) return MATCHING_FAILURE; return READ_OK; } } // namespace scanf_core } // namespace LIBC_NAMESPACE_DECL