add LineEndings module

This commit is contained in:
Josh Holtrop 2016-07-26 22:36:22 -04:00
parent cdae9e51ae
commit 382d155e40
7 changed files with 58 additions and 51 deletions

View File

@ -11,7 +11,7 @@ Buffer::Buffer()
m_file_buffer = nullptr;
m_file_buffer_size = 0u;
m_eol_at_eof = true;
m_line_endings = TextLoader::LINE_ENDING_LF;
m_line_endings = LineEndings::LF;
}
Buffer::~Buffer()
@ -71,26 +71,6 @@ bool Buffer::load_from_file(const char * filename)
bool Buffer::write_to_file(const char * filename)
{
File file;
const char * eol_seq;
size_t eol_len;
switch (m_line_endings)
{
case TextLoader::LINE_ENDING_LF:
eol_seq = "\n";
eol_len = 1u;
break;
case TextLoader::LINE_ENDING_CR:
eol_seq = "\r";
eol_len = 1u;
break;
case TextLoader::LINE_ENDING_CRLF:
eol_seq = "\r\n";
eol_len = 2u;
break;
default:
assert(false);
break;
}
if (!file.open(filename, true))
{
return false;
@ -108,17 +88,19 @@ bool Buffer::write_to_file(const char * filename)
bytes_written += pd->length;
if (pd->eol())
{
if (!file.write((const uint8_t *)eol_seq, eol_len))
if (!file.write(LineEndings::spans[m_line_endings].start,
LineEndings::spans[m_line_endings].length))
{
return false;
}
bytes_written += eol_len;
bytes_written += LineEndings::spans[m_line_endings].length;
}
}
if (m_eol_at_eof && bytes_written > 0u)
{
if (!file.write((const uint8_t *)eol_seq, eol_len))
if (!file.write(LineEndings::spans[m_line_endings].start,
LineEndings::spans[m_line_endings].length))
{
return false;
}

View File

@ -4,6 +4,7 @@
#include <list>
#include <memory>
#include "PieceTable.h"
#include "LineEndings.h"
class Buffer
{
@ -19,7 +20,7 @@ protected:
uint8_t * m_file_buffer;
unsigned long m_file_buffer_size;
bool m_eol_at_eof;
uint8_t m_line_endings;
LineEndings::Type m_line_endings;
void free_file_buffer();
};

11
src/core/LineEndings.cc Normal file
View File

@ -0,0 +1,11 @@
#include "LineEndings.h"
static uint8_t lf[] = "\n";
static uint8_t crlf[] = "\r\n";
static uint8_t cr[] = "\r";
const Span LineEndings::spans[] = {
Span(lf, 1u),
Span(crlf, 2u),
Span(cr, 1u),
};

20
src/core/LineEndings.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef LINEENDINGS_H
#define LINEENDINGS_H
#include "Span.h"
class LineEndings
{
public:
enum Type
{
LF,
CRLF,
CR,
COUNT,
};
static const Span spans[COUNT];
};
#endif

View File

@ -4,7 +4,7 @@
/** Create a TextLoader. */
TextLoader::TextLoader()
{
m_line_endings = LINE_ENDING_LF;
m_line_endings = LineEndings::LF;
m_lines = NULL;
m_eol_at_eof = true;
}
@ -17,12 +17,12 @@ TextLoader::TextLoader()
*/
void TextLoader::load_buffer(uint8_t * buffer, size_t size)
{
std::shared_ptr<std::list<Span>> lines[LINE_ENDING_COUNT];
size_t line_start[LINE_ENDING_COUNT] = {0};
std::shared_ptr<std::list<Span>> lines[LineEndings::COUNT];
size_t line_start[LineEndings::COUNT] = {0};
unsigned int n_cr = 0;
unsigned int n_lf = 0;
bool crlf = true;
for (size_t i = 0; i < LINE_ENDING_COUNT; i++)
for (size_t i = 0; i < LineEndings::COUNT; i++)
{
lines[i] = std::make_shared<std::list<Span>>();
}
@ -30,17 +30,17 @@ void TextLoader::load_buffer(uint8_t * buffer, size_t size)
{
if (buffer[i] == '\r')
{
lines[LINE_ENDING_CR]->push_back(Span(&buffer[line_start[LINE_ENDING_CR]], i - line_start[LINE_ENDING_CR]));
lines[LineEndings::CR]->push_back(Span(&buffer[line_start[LineEndings::CR]], i - line_start[LineEndings::CR]));
n_cr++;
line_start[LINE_ENDING_CR] = i + 1;
line_start[LineEndings::CR] = i + 1;
if (crlf)
{
if ((i < (size - 1)) && (buffer[i + 1] == '\n'))
{
lines[LINE_ENDING_CRLF]->push_back(Span(&buffer[line_start[LINE_ENDING_CRLF]], i - line_start[LINE_ENDING_CRLF]));
lines[LineEndings::CRLF]->push_back(Span(&buffer[line_start[LineEndings::CRLF]], i - line_start[LineEndings::CRLF]));
n_lf++;
i++;
line_start[LINE_ENDING_CRLF] = i + 1;
line_start[LineEndings::CRLF] = i + 1;
}
else
{
@ -50,24 +50,24 @@ void TextLoader::load_buffer(uint8_t * buffer, size_t size)
}
else if (buffer[i] == '\n')
{
lines[LINE_ENDING_LF]->push_back(Span(&buffer[line_start[LINE_ENDING_LF]], i - line_start[LINE_ENDING_LF]));
lines[LineEndings::LF]->push_back(Span(&buffer[line_start[LineEndings::LF]], i - line_start[LineEndings::LF]));
crlf = false;
n_lf++;
line_start[LINE_ENDING_LF] = i + 1;
line_start[LineEndings::LF] = i + 1;
}
}
if (crlf && (n_lf > 0u))
{
m_line_endings = LINE_ENDING_CRLF;
m_line_endings = LineEndings::CRLF;
}
else if ((n_cr > 0u) && (n_lf == 0u))
{
m_line_endings = LINE_ENDING_CR;
m_line_endings = LineEndings::CR;
}
else
{
m_line_endings = LINE_ENDING_LF;
m_line_endings = LineEndings::LF;
}
m_lines = lines[m_line_endings];

View File

@ -5,18 +5,11 @@
#include <list>
#include <memory>
#include "Span.h"
#include "LineEndings.h"
class TextLoader
{
public:
enum
{
LINE_ENDING_LF,
LINE_ENDING_CR,
LINE_ENDING_CRLF,
LINE_ENDING_COUNT
};
TextLoader();
void load_buffer(uint8_t * buffer, size_t size);
size_t num_lines()
@ -30,13 +23,13 @@ public:
return m_lines->size();
}
}
int get_line_endings() { return m_line_endings; }
LineEndings::Type get_line_endings() { return m_line_endings; }
auto begin() { return m_lines->begin(); }
auto end() { return m_lines->end(); }
bool get_eol_at_eof() { return m_eol_at_eof; }
protected:
int m_line_endings;
LineEndings::Type m_line_endings;
bool m_eol_at_eof;
std::shared_ptr<std::list<Span>> m_lines;
};

View File

@ -31,7 +31,7 @@ TEST(TextLoaderTest, detects_lf_line_endings)
TextLoader tl;
auto file = TestSupport::read_file("test/files/line_endings/lf_format.txt");
tl.load_buffer(&(*file)[0], file->size());
EXPECT_EQ(TextLoader::LINE_ENDING_LF, tl.get_line_endings());
EXPECT_EQ(LineEndings::LF, tl.get_line_endings());
ASSERT_EQ(2u, tl.num_lines());
auto it = tl.begin();
EXPECT_EQ("Hello.", line_to_string(it));
@ -45,7 +45,7 @@ TEST(TextLoaderTest, detects_cr_line_endings)
TextLoader tl;
auto file = TestSupport::read_file("test/files/line_endings/cr_format.txt");
tl.load_buffer(&(*file)[0], file->size());
EXPECT_EQ(TextLoader::LINE_ENDING_CR, tl.get_line_endings());
EXPECT_EQ(LineEndings::CR, tl.get_line_endings());
ASSERT_EQ(2u, tl.num_lines());
auto it = tl.begin();
EXPECT_EQ("Hello.", line_to_string(it));
@ -59,7 +59,7 @@ TEST(TextLoaderTest, detects_crlf_line_endings)
TextLoader tl;
auto file = TestSupport::read_file("test/files/line_endings/crlf_format.txt");
tl.load_buffer(&(*file)[0], file->size());
EXPECT_EQ(TextLoader::LINE_ENDING_CRLF, tl.get_line_endings());
EXPECT_EQ(LineEndings::CRLF, tl.get_line_endings());
ASSERT_EQ(2u, tl.num_lines());
auto it = tl.begin();
EXPECT_EQ("Hello.", line_to_string(it));