Repository: llvm/llvm-project
File: libc/src/stdio/baremetal/file_internal.cpp (C++)

Code before:
//===--- Helpers for file I/O on baremetal ----------------------*- C++ -*-===//
//
// 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/baremetal/file_internal.h"

#include "hdr/stdio_macros.h" // for EOF

namespace LIBC_NAMESPACE_DECL {

// Baremetal only exposes three fixed streams now and only stdin supports ungetc
// because stdin is readable - ungetc on stdout/stderr is undefined.
// Only one value is required by the C standard to be stored by ungetc.
extern "C" ::FILE *stdin;

struct UngetcState {
  bool has_value;
  unsigned char value;
};

static UngetcState ungetc_state_stdin{false, 0};

bool pop_ungetc_value(::FILE *stream, unsigned char &out) {
  if (stream != stdin)
    return false;

  if (ungetc_state_stdin.has_value) {
    out = ungetc_state_stdin.value;
    ungetc_state_stdin.has_value = false;
    return true;
  }
  return false;
}

int store_ungetc_value(::FILE *stream, int c) {
  if (c == EOF || stream == nullptr)
    return EOF;


Review comment (suggestion):
This assumes there are only 3 hardcoded streams, but https://github.com/llvm/llvm-project/pull/168931 allows arbitrary streams to be defined by the embedder which wouldn't work with this implementation. To properly support `ungetc`, we might need to introduce a new embedding API (same as for `feof`, `ferror` and `fflush`) but designing it will require further discussion. I'd suggest providing a trivial `ungetc` implementation that always return `EOF` to unblock the libc++ bringup and gives us more time to discuss the shape of the new embedded API.

Code after:
//===--- Helpers for file I/O on baremetal ----------------------*- C++ -*-===//
//
// 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/baremetal/file_internal.h"
#include "src/__support/CPP/optional.h"

#include "hdr/stdio_macros.h" // for EOF, FILE

namespace LIBC_NAMESPACE_DECL {

// Out of standard streams only stdin supports ungetc,
// because stdin is readable - ungetc on stdout/stderr is undefined.
// Only one value is required by the C standard to be stored by ungetc.
// This minimal implementation only handles stdin and returns error on all
// other streams.
// TODO: Shall we have an embedding API for ungetc?

static cpp::optional<unsigned char> ungetc_state_stdin;

bool pop_ungetc_value(::FILE *stream, unsigned char &out) {
  if (stream != stdin)
    return false;

  if (!ungetc_state_stdin)
    return false;

  out = *ungetc_state_stdin;
  ungetc_state_stdin.reset();
  return true;
}

int push_ungetc_value(::FILE *stream, int c) {
  if (c == EOF || stream == nullptr)
    return EOF;

  if (stream != stdin)
    return EOF;