82 lines · cpp
1//===-- Implementation of perror ------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "src/stdio/perror.h"10#include "src/__support/CPP/string_view.h"11#include "src/__support/File/file.h"12#include "src/__support/StringUtil/error_to_string.h"13#include "src/__support/libc_errno.h"14#include "src/__support/macros/config.h"15 16namespace LIBC_NAMESPACE_DECL {17 18static int write_out(cpp::string_view str_view, File *f) {19 if (str_view.size() > 0) {20 auto result = f->write_unlocked(str_view.data(), str_view.size());21 if (result.has_error())22 return result.error;23 }24 return 0;25}26 27// separate function so that we can return early on error but still get the28// unlock. This function sets errno and should not be called elsewhere.29static void write_sequence(cpp::string_view str_view,30 cpp::string_view err_str) {31 int write_err;32 // TODO: this seems like there should be some sort of queue system to33 // deduplicate this code.34 35 // FORMAT:36 // if str != nullptr and doesn't start with a null byte:37 // "[str]: [strerror(errno)]\n"38 // else39 // "[strerror(errno)]\n"40 if (str_view.size() > 0) {41 write_err = write_out(str_view, LIBC_NAMESPACE::stderr);42 if (write_err != 0) {43 libc_errno = write_err;44 return;45 }46 47 write_err = write_out(": ", LIBC_NAMESPACE::stderr);48 if (write_err != 0) {49 libc_errno = write_err;50 return;51 }52 }53 54 write_err = write_out(err_str, LIBC_NAMESPACE::stderr);55 if (write_err != 0) {56 libc_errno = write_err;57 return;58 }59 60 write_err = write_out("\n", LIBC_NAMESPACE::stderr);61 if (write_err != 0) {62 libc_errno = write_err;63 return;64 }65}66 67LLVM_LIBC_FUNCTION(void, perror, (const char *str)) {68 const char empty_str[1] = {'\0'};69 if (str == nullptr)70 str = empty_str;71 cpp::string_view str_view(str);72 73 cpp::string_view err_str = get_error_string(libc_errno);74 75 // We need to lock the stream to ensure the newline is always appended.76 LIBC_NAMESPACE::stderr->lock();77 write_sequence(str_view, err_str);78 LIBC_NAMESPACE::stderr->unlock();79}80 81} // namespace LIBC_NAMESPACE_DECL82