• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)24 int 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