blob: bdbb5c87f75e55914d1bcd6f72c3d0aa54c773f8 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
//===-- 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/stdio/scanf_core/core_structs.h"
#include "src/stdio/scanf_core/reader.h"
#include <stddef.h>
namespace __llvm_libc {
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<size_t>::max();
}
}
char *output = reinterpret_cast<char *>(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 __llvm_libc
|