//===-- 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