<commit_before>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: <NAME> <<EMAIL>>
 */

#include "sys.hpp"
#include <ch.hpp>
#include <hal.h>
#include <chprintf.h>
#include <memstreams.h>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdarg>


namespace os
{

static MUTEX_DECL(_mutex);  ///< Doesn't require initialization
static char _buffer[256];

static BaseSequentialStream* _stdout_stream = (BaseSequentialStream*)&STDOUT_SD;

static void writeExpandingCrLf(BaseSequentialStream* stream, const char* str)
{
    for (const char* pc = str; *pc != '\0'; pc++)
    {
        if (*pc == '\n')
        {
            chSequentialStreamPut(stream, '\r');
        }
        chSequentialStreamPut(stream, *pc);
    }
}

static void genericPrint(BaseSequentialStream* stream, const char* format, va_list vl)
{
    /*
     * Printing the string into the buffer using chvprintf()
     */
    MemoryStream ms;
    msObjectInit(&ms, (uint8_t*)_buffer, sizeof(_buffer), 0);

    BaseSequentialStream* chp = (BaseSequentialStream*)&ms;
    chvprintf(chp, format, vl);

    chSequentialStreamPut(chp, 0);

    /*
     * Writing the buffer replacing "\n" --> "\r\n"
     */
    chMtxLock(&_mutex);
    writeExpandingCrLf(stream, _buffer);
    chMtxUnlock(&_mutex);
}

void lowsyslog(const char* format, ...)
{
    va_list vl;
    va_start(vl, format);
    genericPrint((BaseSequentialStream*)&STDOUT_SD, format, vl);   // Lowsyslog is always directed to STDOUT_SD
    va_end(vl);
}


void setStdOutStream(BaseSequentialStream* stream)
{
    _stdout_stream = stream;
}

} // namespace os

extern "C"
{

using namespace os;

int printf(const char* format, ...)
{
    va_list vl;
    va_start(vl, format);
    genericPrint(_stdout_stream, format, vl);
    va_end(vl);
    return std::strlen(format);   // This is not standard compliant, but ain't nobody cares about what printf() returns
}

int vprintf(const char* format, va_list vl)
{
    genericPrint(_stdout_stream, format, vl);
    return std::strlen(format);
}

int puts(const char* str)
{
    chMtxLock(&_mutex);
    writeExpandingCrLf(_stdout_stream, str);
    writeExpandingCrLf(_stdout_stream, "\n");
    chMtxUnlock(&_mutex);
    return std::strlen(str) + 2;
}

}<commit_msg>Fixed race condition in stdout handling<commit_after>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: <NAME> <<EMAIL>>
 */

#include "sys.hpp"
#include <ch.hpp>
#include <hal.h>
#include <chprintf.h>
#include <memstreams.h>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdarg>


namespace os
{

static chibios_rt::Mutex mutex_;
static char buffer_[256];

static BaseSequentialStream* stdout_stream_ = (BaseSequentialStream*)&STDOUT_SD;

static void writeExpandingCrLf(BaseSequentialStream* stream, const char* str)
{
    for (const char* pc = str; *pc != '\0'; pc++)
    {
        if (*pc == '\n')
        {
            chSequentialStreamPut(stream, '\r');
        }
        chSequentialStreamPut(stream, *pc);
    }
}

static void genericPrint(BaseSequentialStream* stream, const char* format, va_list vl)
{
    MutexLocker locker(mutex_);

    /*
     * Printing the string into the buffer using chvprintf()
     */
    MemoryStream ms;
    msObjectInit(&ms, (uint8_t*)buffer_, sizeof(buffer_), 0);

    BaseSequentialStream* chp = (BaseSequentialStream*)&ms;
    chvprintf(chp, format, vl);

    chSequentialStreamPut(chp, 0);

    /*
     * Writing the buffer replacing "\n" --> "\r\n"
     */
    writeExpandingCrLf(stream, buffer_);
}

void lowsyslog(const char* format, ...)
{
    va_list vl;
    va_start(vl, format);
    genericPrint((BaseSequentialStream*)&STDOUT_SD, format, vl);   // Lowsyslog is always directed to STDOUT_SD
    va_end(vl);
}


void setStdOutStream(BaseSequentialStream* stream)
{
    stdout_stream_ = stream;
}

} // namespace os

extern "C"
{

using namespace os;

int printf(const char* format, ...)
{
    va_list vl;
    va_start(vl, format);
    genericPrint(stdout_stream_, format, vl);
    va_end(vl);
    return std::strlen(format);   // This is not standard compliant, but ain't nobody cares about what printf() returns
}

int vprintf(const char* format, va_list vl)
{
    genericPrint(stdout_stream_, format, vl);
    return std::strlen(format);
}

int puts(const char* str)
{
    MutexLocker locker(mutex_);
    writeExpandingCrLf(stdout_stream_, str);
    writeExpandingCrLf(stdout_stream_, "\n");
    return std::strlen(str) + 2;
}

}
{'fraction_non_alphanumeric': 0.13285340314136126, 'fraction_numerical': 0.005235602094240838, 'mean_word_length': 3.7170781893004117, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2471266', 'n_tokens_mistral': 1603, 'n_tokens_neox': 1564, 'n_words': 393}