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-exception
6//
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 the
28// 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 to
33 // deduplicate this code.
34
35 // FORMAT:
36 // if str != nullptr and doesn't start with a null byte:
37 // "[str]: [strerror(errno)]\n"
38 // else
39 // "[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_DECL
82

source code of libc/src/stdio/generic/perror.cpp