blob: 68b4ad644caab7cd90c9f2a708a842ed889bb763 [file] [log] [blame]
//===-- Implementation of perror ------------------------------------------===//
//
// 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/perror.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/File/file.h"
#include "src/__support/StringUtil/error_to_string.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
static int write_out(cpp::string_view str_view, File *f) {
if (str_view.size() > 0) {
auto result = f->write_unlocked(str_view.data(), str_view.size());
if (result.has_error())
return result.error;
}
return 0;
}
// separate function so that we can return early on error but still get the
// unlock. This function sets errno and should not be called elsewhere.
static void write_sequence(cpp::string_view str_view,
cpp::string_view err_str) {
int write_err;
// TODO: this seems like there should be some sort of queue system to
// deduplicate this code.
// FORMAT:
// if str != nullptr and doesn't start with a null byte:
// "[str]: [strerror(errno)]\n"
// else
// "[strerror(errno)]\n"
if (str_view.size() > 0) {
write_err = write_out(str_view, LIBC_NAMESPACE::stderr);
if (write_err != 0) {
libc_errno = write_err;
return;
}
write_err = write_out(": ", LIBC_NAMESPACE::stderr);
if (write_err != 0) {
libc_errno = write_err;
return;
}
}
write_err = write_out(err_str, LIBC_NAMESPACE::stderr);
if (write_err != 0) {
libc_errno = write_err;
return;
}
write_err = write_out("\n", LIBC_NAMESPACE::stderr);
if (write_err != 0) {
libc_errno = write_err;
return;
}
}
LLVM_LIBC_FUNCTION(void, perror, (const char *str)) {
const char empty_str[1] = {'\0'};
if (str == nullptr)
str = empty_str;
cpp::string_view str_view(str);
cpp::string_view err_str = get_error_string(libc_errno);
// We need to lock the stream to ensure the newline is always appended.
LIBC_NAMESPACE::stderr->lock();
write_sequence(str_view, err_str);
LIBC_NAMESPACE::stderr->unlock();
}
} // namespace LIBC_NAMESPACE_DECL