| // Copyright 2023 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| #include <cpp-string/string_printf.h> |
| #include <errno.h> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <stdio.h> |
| |
| namespace bt_lib_cpp_string { |
| namespace { |
| |
| void StringVAppendfHelper(std::string* dest, const char* format, va_list ap) { |
| // Size of the small stack buffer to use. This should be kept in sync |
| // with the numbers in StringPrintfTest. |
| constexpr size_t kStackBufferSize = 1024u; |
| |
| char stack_buf[kStackBufferSize]; |
| // |result| is the number of characters that would have been written if |
| // kStackBufferSize were sufficiently large, not counting the terminating null |
| // character. |vsnprintf()| always null-terminates! |
| int result = vsnprintf(stack_buf, kStackBufferSize, format, ap); |
| if (result < 0) { |
| // As far as I can tell, we'd only get |EOVERFLOW| if the result is so large |
| // that it can't be represented by an |int| (in which case retrying would be |
| // futile), so Chromium's implementation is wrong. |
| return; |
| } |
| |
| // Only append what fit into our stack buffer. |
| // Strings that are too long will be truncated. |
| size_t actual_len_excluding_null = result; |
| if (actual_len_excluding_null > kStackBufferSize - 1) { |
| actual_len_excluding_null = kStackBufferSize - 1; |
| } |
| dest->append(stack_buf, actual_len_excluding_null); |
| } |
| |
| } // namespace |
| |
| std::string StringPrintf(const char* format, ...) { |
| va_list ap; |
| va_start(ap, format); |
| std::string rv; |
| StringVAppendf(&rv, format, ap); |
| va_end(ap); |
| return rv; |
| } |
| |
| std::string StringVPrintf(const char* format, va_list ap) { |
| std::string rv; |
| StringVAppendf(&rv, format, ap); |
| return rv; |
| } |
| |
| void StringAppendf(std::string* dest, const char* format, ...) { |
| va_list ap; |
| va_start(ap, format); |
| StringVAppendf(dest, format, ap); |
| va_end(ap); |
| } |
| |
| void StringVAppendf(std::string* dest, const char* format, va_list ap) { |
| int old_errno = errno; |
| StringVAppendfHelper(dest, format, ap); |
| errno = old_errno; |
| } |
| |
| } // namespace bt_lib_cpp_string |