1// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "absl/strings/internal/str_format/output.h"
16
17#include <errno.h>
18#include <cstring>
19
20namespace absl {
21namespace str_format_internal {
22
23namespace {
24struct ClearErrnoGuard {
25 ClearErrnoGuard() : old_value(errno) { errno = 0; }
26 ~ClearErrnoGuard() {
27 if (!errno) errno = old_value;
28 }
29 int old_value;
30};
31} // namespace
32
33void BufferRawSink::Write(string_view v) {
34 size_t to_write = std::min(v.size(), size_);
35 std::memcpy(buffer_, v.data(), to_write);
36 buffer_ += to_write;
37 size_ -= to_write;
38 total_written_ += v.size();
39}
40
41void FILERawSink::Write(string_view v) {
42 while (!v.empty() && !error_) {
43 // Reset errno to zero in case the libc implementation doesn't set errno
44 // when a failure occurs.
45 ClearErrnoGuard guard;
46
47 if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) {
48 // Some progress was made.
49 count_ += result;
50 v.remove_prefix(result);
51 } else {
52 if (errno == EINTR) {
53 continue;
54 } else if (errno) {
55 error_ = errno;
56 } else if (std::ferror(output_)) {
57 // Non-POSIX compliant libc implementations may not set errno, so we
58 // have check the streams error indicator.
59 error_ = EBADF;
60 } else {
61 // We're likely on a non-POSIX system that encountered EINTR but had no
62 // way of reporting it.
63 continue;
64 }
65 }
66 }
67}
68
69} // namespace str_format_internal
70} // namespace absl
71