245 lines
4.9 KiB
C++
245 lines
4.9 KiB
C++
|
|
#include <stdio.h>
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <stdarg.h>
|
|
#include "os/tools/printf_helper.hpp"
|
|
#include "os/tools/ringbuffer.hpp"
|
|
|
|
#if defined(__baos_kernel_source__)
|
|
#include "os/serial.hpp"
|
|
#include "os/tty.hpp"
|
|
#else
|
|
#include "os/syscall.hpp"
|
|
#endif
|
|
|
|
struct __file
|
|
{
|
|
protected:
|
|
static constexpr unsigned BUFFER_SIZE = 4096;
|
|
|
|
baos::RingBuffer<char, BUFFER_SIZE> mBuffer;
|
|
bool mEof = false;
|
|
bool mError = false;
|
|
protected:
|
|
virtual bool underflow() noexcept = 0;
|
|
public:
|
|
[[nodiscard]] bool isEof() const noexcept { return mEof; }
|
|
[[nodiscard]] bool isError() const noexcept { return mError; }
|
|
|
|
bool readChar(char& outChar) noexcept
|
|
{
|
|
while (!mBuffer.next(outChar)) {
|
|
if (!underflow()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool readLine(std::string& outLine) noexcept
|
|
{
|
|
outLine.clear();
|
|
while(true)
|
|
{
|
|
while (mBuffer.empty()) {
|
|
if (!underflow()) {
|
|
return false;
|
|
}
|
|
}
|
|
// first check if there is a \n in the stream
|
|
std::size_t count = mBuffer.size();
|
|
for (std::size_t idx = 0; idx < mBuffer.size(); ++idx)
|
|
{
|
|
if (mBuffer[idx] == '\n')
|
|
{
|
|
count = idx + 1;
|
|
break;
|
|
}
|
|
}
|
|
outLine.reserve(outLine.size() + count);
|
|
for (std::size_t idx = 0; idx < count; ++idx)
|
|
{
|
|
char chr = '\0';
|
|
mBuffer.next(chr);
|
|
outLine.append(chr);
|
|
}
|
|
|
|
if (outLine.back() == '\n')
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
namespace
|
|
{
|
|
struct RegularPrinter
|
|
{
|
|
void putchar(int chr) noexcept // NOLINT
|
|
{
|
|
::putchar(chr);
|
|
}
|
|
};
|
|
|
|
struct BufferPrinter
|
|
{
|
|
char* pos = nullptr;
|
|
char* end = nullptr;
|
|
|
|
void putchar(int chr) noexcept // NOLINT
|
|
{
|
|
if (pos != end)
|
|
{
|
|
*pos = static_cast<char>(chr);
|
|
++pos;
|
|
}
|
|
}
|
|
};
|
|
|
|
class StdinFile : public __file
|
|
{
|
|
public:
|
|
bool underflow() noexcept override
|
|
{
|
|
#if defined(__baos_kernel_source__)
|
|
for (char chr : tty::readLine()) {
|
|
mBuffer.append(chr);
|
|
}
|
|
return true;
|
|
#else
|
|
return false; // TODO!!!
|
|
#endif
|
|
}
|
|
};
|
|
StdinFile gStdin;
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
FILE* __stdin = &gStdin;
|
|
|
|
// TODO: line-buffering
|
|
int putchar(int chr) noexcept
|
|
{
|
|
#if defined(__baos_kernel_source__)
|
|
tty::putChar(static_cast<char>(chr));
|
|
if (chr == '\n')
|
|
{
|
|
serialWrite(PORT_COM1, '\r');
|
|
serialWrite(PORT_COM1, '\n');
|
|
}
|
|
else
|
|
{
|
|
serialWrite(PORT_COM1, static_cast<std::uint8_t>(chr));
|
|
}
|
|
return 0;
|
|
#else
|
|
char asChar = static_cast<char>(chr);
|
|
baos::doSyscall(baos::Syscall::FILE_WRITE, 0, &asChar, 1);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int puts(const char* str) noexcept
|
|
{
|
|
#if defined(__baos_kernel_source__)
|
|
while (*str)
|
|
{
|
|
putchar(*str);
|
|
++str;
|
|
}
|
|
putchar('\n');
|
|
return 0;
|
|
#else
|
|
baos::doSyscall(baos::Syscall::FILE_WRITE, 0, str, std::strlen(str));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int printf(const char* format, ...) noexcept
|
|
{
|
|
va_list parameters;
|
|
va_start(parameters, format);
|
|
const int result = vprintf(format, parameters);
|
|
va_end(parameters);
|
|
return result;
|
|
}
|
|
|
|
int vprintf(const char* format, va_list vlist) BA_CXX_NOEXCEPT
|
|
{
|
|
return baos::PrintFHelper<RegularPrinter>().vprintf(format, vlist);
|
|
}
|
|
|
|
int snprintf(char* buffer, size_t bufferSize, const char* format, ...) noexcept
|
|
{
|
|
va_list parameters;
|
|
va_start(parameters, format);
|
|
const int result = vsnprintf(buffer, bufferSize, format, parameters);
|
|
va_end(parameters);
|
|
return result;
|
|
}
|
|
|
|
int vsnprintf(char* buffer, size_t bufferSize, const char* format, va_list vlist) noexcept
|
|
{
|
|
BufferPrinter printer{
|
|
.pos = buffer,
|
|
.end = bufferSize > 0 ? buffer + bufferSize - 1 : buffer
|
|
};
|
|
const int length = baos::PrintFHelper(printer).vprintf(format, vlist);
|
|
if (bufferSize > 0)
|
|
{
|
|
buffer[std::min(static_cast<int>(bufferSize - 1), length)] = '\0';
|
|
}
|
|
return length;
|
|
}
|
|
|
|
int fgetc(FILE* stream) noexcept
|
|
{
|
|
char chr;
|
|
if (!stream->readChar(chr))
|
|
{
|
|
return EOF;
|
|
}
|
|
return chr;
|
|
}
|
|
|
|
char* fgets(char* buffer, int count, FILE* stream) noexcept
|
|
{
|
|
if (count < 1) {
|
|
return nullptr;
|
|
}
|
|
if (count == 1)
|
|
{
|
|
*buffer = '\0';
|
|
return buffer;
|
|
}
|
|
|
|
int pos = 0;
|
|
for (; pos < count - 1; ++pos)
|
|
{
|
|
if (!stream->readChar(buffer[pos]))
|
|
{
|
|
if (stream->isError() || pos == 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
buffer[pos] = '\0';
|
|
return buffer;
|
|
}
|
|
} // extern "C"
|
|
|
|
namespace std
|
|
{
|
|
bool fgetline(FILE* stream, std::string& outLine) noexcept
|
|
{
|
|
return stream->readLine(outLine);
|
|
}
|
|
}
|
|
|