1 //===-- String type specifier converters for scanf --------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_STRING_CONVERTER_H 10 #define LLVM_LIBC_SRC_STDIO_SCANF_CORE_STRING_CONVERTER_H 11 12 #include "src/__support/CPP/limits.h" 13 #include "src/__support/ctype_utils.h" 14 #include "src/__support/macros/config.h" 15 #include "src/stdio/scanf_core/core_structs.h" 16 #include "src/stdio/scanf_core/reader.h" 17 18 #include <stddef.h> 19 20 namespace LIBC_NAMESPACE_DECL { 21 namespace scanf_core { 22 23 template <typename T> convert_string(Reader<T> * reader,const FormatSection & to_conv)24int convert_string(Reader<T> *reader, const FormatSection &to_conv) { 25 // %s "Matches a sequence of non-white-space characters" 26 27 // %c "Matches a sequence of characters of exactly the number specified by the 28 // field width (1 if no field width is present in the directive)" 29 30 // %[ "Matches a nonempty sequence of characters from a set of expected 31 // characters (the scanset)." 32 size_t max_width = 0; 33 if (to_conv.max_width > 0) { 34 max_width = to_conv.max_width; 35 } else { 36 if (to_conv.conv_name == 'c') { 37 max_width = 1; 38 } else { 39 max_width = cpp::numeric_limits<size_t>::max(); 40 } 41 } 42 43 char *output = reinterpret_cast<char *>(to_conv.output_ptr); 44 45 char cur_char = reader->getc(); 46 size_t i = 0; 47 for (; i < max_width && cur_char != '\0'; ++i) { 48 // If this is %s and we've hit a space, or if this is %[] and we've found 49 // something not in the scanset. 50 if ((to_conv.conv_name == 's' && internal::isspace(cur_char)) || 51 (to_conv.conv_name == '[' && !to_conv.scan_set.test(cur_char))) { 52 break; 53 } 54 // if the NO_WRITE flag is not set, write to the output. 55 if ((to_conv.flags & NO_WRITE) == 0) 56 output[i] = cur_char; 57 cur_char = reader->getc(); 58 } 59 60 // We always read one more character than will be used, so we have to put the 61 // last one back. 62 reader->ungetc(cur_char); 63 64 // If this is %s or %[] 65 if (to_conv.conv_name != 'c' && (to_conv.flags & NO_WRITE) == 0) { 66 // Always null terminate the string. This may cause a write to the 67 // (max_width + 1) byte, which is correct. The max width describes the max 68 // number of characters read from the input string, and doesn't necessarily 69 // correspond to the output. 70 output[i] = '\0'; 71 } 72 73 if (i == 0) 74 return MATCHING_FAILURE; 75 return READ_OK; 76 } 77 78 } // namespace scanf_core 79 } // namespace LIBC_NAMESPACE_DECL 80 81 #endif // LLVM_LIBC_SRC_STDIO_SCANF_CORE_STRING_CONVERTER_H 82