// 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 #include #include #include #include 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