• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <cstddef>
17 #include <span>
18 #include <string_view>
19 
20 #include "pw_assert/assert.h"
21 #include "pw_result/result.h"
22 #include "pw_status/status.h"
23 #include "pw_status/status_with_size.h"
24 #include "pw_string/internal/length.h"
25 
26 namespace pw {
27 namespace string {
28 
29 // Safe alternative to the string_view constructor to avoid the risk of an
30 // unbounded implicit or explicit use of strlen.
31 //
32 // This is strongly recommended over using something like C11's strnlen_s as
33 // a string_view does not require null-termination.
ClampedCString(std::span<const char> str)34 constexpr std::string_view ClampedCString(std::span<const char> str) {
35   return std::string_view(str.data(),
36                           internal::ClampedLength(str.data(), str.size()));
37 }
38 
ClampedCString(const char * str,size_t max_len)39 constexpr std::string_view ClampedCString(const char* str, size_t max_len) {
40   return ClampedCString(std::span<const char>(str, max_len));
41 }
42 
43 // Safe alternative to strlen to calculate the null-terminated length of the
44 // string within the specified span, excluding the null terminator. Like C11's
45 // strnlen_s, the scan for the null-terminator is bounded.
46 //
47 // Returns:
48 //   null-terminated length of the string excluding the null terminator.
49 //   OutOfRange - if the string is not null-terminated.
50 //
51 // Precondition: The string shall be at a valid pointer.
NullTerminatedLength(std::span<const char> str)52 constexpr pw::Result<size_t> NullTerminatedLength(std::span<const char> str) {
53   PW_DASSERT(str.data() != nullptr);
54 
55   const size_t length = internal::ClampedLength(str.data(), str.size());
56   if (length == str.size()) {
57     return Status::OutOfRange();
58   }
59 
60   return length;
61 }
62 
NullTerminatedLength(const char * str,size_t max_len)63 constexpr pw::Result<size_t> NullTerminatedLength(const char* str,
64                                                   size_t max_len) {
65   return NullTerminatedLength(std::span<const char>(str, max_len));
66 }
67 
68 // Copies the source string to the dest, truncating if the full string does not
69 // fit. Always null terminates if dest.size() or num > 0.
70 //
71 // Returns the number of characters written, excluding the null terminator. If
72 // the string is truncated, the status is ResourceExhausted.
73 //
74 // Precondition: The destination and source shall not overlap.
75 // Precondition: The source shall be a valid pointer.
Copy(const std::string_view & source,std::span<char> dest)76 PW_CONSTEXPR_CPP20 inline StatusWithSize Copy(const std::string_view& source,
77                                               std::span<char> dest) {
78   if (dest.empty()) {
79     return StatusWithSize::ResourceExhausted();
80   }
81 
82   const size_t copied = source.copy(dest.data(), dest.size() - 1);
83   dest[copied] = '\0';
84 
85   return StatusWithSize(
86       copied == source.size() ? OkStatus() : Status::ResourceExhausted(),
87       copied);
88 }
89 
Copy(const char * source,std::span<char> dest)90 PW_CONSTEXPR_CPP20 inline StatusWithSize Copy(const char* source,
91                                               std::span<char> dest) {
92   PW_DASSERT(source != nullptr);
93   return Copy(ClampedCString(source, dest.size()), dest);
94 }
95 
Copy(const char * source,char * dest,size_t num)96 PW_CONSTEXPR_CPP20 inline StatusWithSize Copy(const char* source,
97                                               char* dest,
98                                               size_t num) {
99   return Copy(source, std::span<char>(dest, num));
100 }
101 
102 }  // namespace string
103 }  // namespace pw
104