blob: a43e8b9ca7c0521236c43d8641a1beb7e23b859b [file] [log] [blame]
// 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