Start working on build system.

This commit is contained in:
jmsgrogan 2023-12-20 16:58:22 +00:00
parent 4b308f6c32
commit 521486be62
88 changed files with 1065 additions and 349 deletions

View file

@ -2,19 +2,29 @@
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
SOURCE_DIR=$SCRIPT_DIR/src
CORE_SRC_DIR=$SOURCE_DIR/base/core
g++ $SOURCE_DIR/main.cpp \
$SOURCE_DIR/base/core/base_types/Error.cpp \
$SOURCE_DIR/base/core/base_types/Index.cpp \
$SOURCE_DIR/base/core/data_structures/String.cpp \
$SOURCE_DIR/base/core/file_utilities/FileSystemPath.cpp \
$SOURCE_DIR/base/core/file_utilities/File.cpp \
$SOURCE_DIR/base/core/file_utilities/Directory.cpp \
$SOURCE_DIR/base/core/encoding/CharUtils.cpp \
$CORE_SRC_DIR/base_types/Error.cpp \
$CORE_SRC_DIR/base_types/Index.cpp \
$SOURCE_DIR/base/compiler/BuildLibrary.cpp \
$SOURCE_DIR/base/compiler/BuildSession.cpp \
$CORE_SRC_DIR/data_structures/String.cpp \
$CORE_SRC_DIR/encoding/CharUtils.cpp \
$CORE_SRC_DIR/filesystem/FileSystemPath.cpp \
$CORE_SRC_DIR/filesystem/File.cpp \
$CORE_SRC_DIR/filesystem/Directory.cpp \
$CORE_SRC_DIR/logging/ConsoleLogger.cpp \
$CORE_SRC_DIR/logging/Logger.cpp \
$CORE_SRC_DIR/time/Time.cpp \
-o builder -g -fno-exceptions -fno-rtti \
-I$SOURCE_DIR/base/core/data_structures \
-I$SOURCE_DIR/base/core/base_types \
-I$SOURCE_DIR/base/core/memory \
-I$SOURCE_DIR/base/core/loggers \
-I$SOURCE_DIR/base/core/encoding \
-I$SOURCE_DIR/base/core/file_utilities
-I$CORE_SRC_DIR/base_types \
-I$SOURCE_DIR/base/compiler \
-I$CORE_SRC_DIR/data_structures \
-I$CORE_SRC_DIR/encoding \
-I$CORE_SRC_DIR/filesystem \
-I$CORE_SRC_DIR/logging \
-I$CORE_SRC_DIR/memory \
-I$CORE_SRC_DIR/system/process \
-I$CORE_SRC_DIR/time

View file

@ -0,0 +1,25 @@
#include "BuildLibrary.h"
#include "Logger.h"
#include "Directory.h"
BuildLibrary::BuildLibrary(const FileSystemPath& build_config)
: m_build_config(build_config)
{
}
Status BuildLibrary::scan()
{
LOG_INFO("Scanning build file at: " << m_build_config);
const auto search_dir = m_build_config.parent_path();
const auto status = Directory::getFilesWithExtension(search_dir,
".cpp",
m_sources,
true);
return status;
}
const Vector<FileSystemPath>& BuildLibrary::get_sources() const
{
return m_sources;
}

View file

@ -0,0 +1,22 @@
#pragma once
#include "FileSystemPath.h"
#include "String.h"
class BuildLibrary
{
public:
BuildLibrary() = default;
BuildLibrary(const FileSystemPath& build_config);
Status scan();
const Vector<FileSystemPath>& get_sources() const;
private:
FileSystemPath m_build_config;
Vector<FileSystemPath> m_sources;
Vector<FileSystemPath> m_includes;
String m_name;
};

View file

@ -0,0 +1,73 @@
#include "BuildSession.h"
#include "Logger.h"
#include "Process.h"
#include "Directory.h"
BuildSession::BuildSession(const String& source_dir,
const String& build_dir)
: m_source_dir(source_dir)
{
if (build_dir.empty())
{
m_build_dir = FileSystemPath::current_dir().value();
}
else
{
m_build_dir = build_dir;
}
}
Status BuildSession::scan()
{
LOG_INFO("Scanning sources at:" << m_source_dir);
Vector<FileSystemPath> toml_files;
STATUS_CHECK(Directory::getFilesWithExtension(
m_source_dir,
".toml",
toml_files,
true), "Error looking for build files");
for(const auto& toml_file : toml_files)
{
if (toml_file.file_name() == "build")
{
STATUS_CHECK(add_library(toml_file),
"Error adding library");
}
}
return {};
}
Status BuildSession::add_library(const FileSystemPath& config_path)
{
LOG_INFO("Adding library at: " << config_path);
BuildLibrary lib(config_path);
STATUS_CHECK(lib.scan(), "Error scanning library");
m_libraries.push_back(lib);
return {};
}
Status BuildSession::build()
{
for(const auto& library : m_libraries)
{
for(const auto& source : library.get_sources())
{
String compiler_command = m_compiler_command + " -c ";
compiler_command += source.str() + " ";
LOG_INFO("Running command: " << compiler_command);
const auto self_name = Process::get_self_name();
if (!self_name.ok())
{
return Status(self_name.error());
}
LOG_INFO("Self name is: " << self_name.value());
break;
}
break;
}
return {};
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "BuildLibrary.h"
#include "Error.h"
class BuildSession
{
public:
BuildSession(const String& source_dir,
const String& build_dir = {});
Status scan();
Status build();
Status add_library(const FileSystemPath& config_path);
private:
String m_compiler_command{"g++"};
String m_compiler_flags{"-g -fno-exceptions -fno-rtti"};
FileSystemPath m_source_dir;
FileSystemPath m_build_dir;
Vector<BuildLibrary> m_libraries;
};

View file

@ -1,5 +1,8 @@
#include "Error.h"
#include <string.h>
#include <errno.h>
Error::Error(const String& msg)
: m_message(msg)
{
@ -9,3 +12,32 @@ const String& Error::msg() const
{
return m_message;
}
String Error::from_errno()
{
return ::strerror(errno);
}
Status::Status(const Error& err)
: m_error(err),
m_ok(false)
{
}
void Status::on_errno(const String& prefix_msg)
{
String errno_msg(::strerror(errno));
m_error = Error(prefix_msg + " | " + errno_msg);
m_ok = false;
}
const Error& Status::error() const
{
return m_error;
}
bool Status::ok() const
{
return m_ok;
}

View file

@ -2,6 +2,31 @@
#include "String.h"
#define IF_OK_AND_TRUE(PRED) \
const auto _result = PRED; \
if (!_result.ok()){return Status(_result.error());} \
if (_result.value())
#define ERROR_IF_NOT_OK_OR_TRUE(PRED, msg) \
{const auto _result = PRED; \
if (!_result.ok()){return {_result.error()};} \
if (!_result.value()){return {Error(msg)};}}
#define ON_ERRNO(msg) \
{Status _status; \
_status.on_errno("Failed to get directory content in opendir"); \
return _status;} \
#define ON_ERRNO_RESULT(msg) \
return {Error(_s(msg) + " | " + Error::from_errno())};
#define STATUS_CHECK(PRED, error_msg) \
{const auto _status = PRED; \
if (!_status.ok()){ \
const auto message = _s(error_msg) + "|" + _status.error().msg(); \
return Status(Error(message)); \
}}
class Error
{
public:
@ -10,6 +35,26 @@ public:
Error() = default;
const String& msg() const;
static String from_errno();
private:
String m_message;
};
class Status
{
public:
Status() = default;
Status(const Error& err);
void on_errno(const String& prefix_msg);
const Error& error() const;
bool ok() const;
private:
Error m_error;
bool m_ok{true};
};

View file

@ -6,7 +6,7 @@ template<typename T>
class Result
{
public:
Result(const T& val)
Result(const T& val = T())
: m_value(val)
{
@ -19,6 +19,12 @@ public:
}
void on_error(const Error& error)
{
m_error = error;
m_ok = false;
}
const Error& error() const
{
return m_error;
@ -34,6 +40,11 @@ public:
return m_value;
}
T& value()
{
return m_value;
}
private:
T m_value;
Error m_error;

View file

@ -1,6 +1,7 @@
#include "String.h"
#include <stdio.h>
#include <stdarg.h>
String::String()
{
@ -17,6 +18,49 @@ String::String(const char* data)
append(data);
}
String String::fmt(const char* fmt, ...)
{
String ret;
va_list args;
va_start(args, fmt);
char format_delim = '%';
bool in_format = false;
while(*fmt != '\0')
{
if (*fmt == format_delim)
{
in_format = true;
}
else if(in_format && *fmt == 's')
{
in_format = false;
const auto s = va_arg(args, char*);
ret.append(s);
}
else if(in_format && *fmt == 'd')
{
in_format = false;
const auto i = va_arg(args, int);
ret += to_string(i);
}
else if(in_format && *fmt == 'c')
{
in_format = false;
const auto c = va_arg(args, int);
ret +=c;
}
else
{
ret += *fmt;
}
++fmt;
}
va_end(args);
return ret;
}
void String::append(const char* data)
{
if (data == nullptr)
@ -26,9 +70,18 @@ void String::append(const char* data)
}
auto loc = data;
bool first=true;
while(*loc != '\0')
{
if (!m_data.empty() && first)
{
m_data[m_data.size() - 1] = *loc;
}
else
{
m_data.push_back(*loc);
}
first = false;
loc++;
}
m_data.push_back('\0');
@ -46,7 +99,7 @@ bool String::empty() const
void String::append(const Vector<Byte>& data)
{
if (data.capacity() == 0)
if (data.empty())
{
m_data.push_back('\0');
return;
@ -79,7 +132,7 @@ Pair<String, String> String::rsplit(char c) const
slice(0, index.value(), left);
String right;
slice(index.value(), size(), right);
slice(index.value() + 1, size(), right);
return {left, right};
}
return {*this, {}};
@ -87,7 +140,7 @@ Pair<String, String> String::rsplit(char c) const
bool String::slice(std::size_t idx, String& out) const
{
if (idx >= m_data.size() - 1)
if (idx >= m_data.size())
{
return false;
}
@ -102,7 +155,7 @@ bool String::slice(std::size_t idx, String& out) const
bool String::slice(std::size_t start, std::size_t end, String& out) const
{
if (end >= m_data.size() - 1)
if (end >= m_data.size())
{
return false;
}
@ -181,6 +234,12 @@ String& String::operator<<(const char* body)
return *this;
}
String& String::operator<<(const String& body)
{
*this += body;
return *this;
}
bool String::operator==(const String& other) const
{
return m_data == other.m_data;
@ -193,12 +252,7 @@ bool String::operator!=(const String& other) const
String& String::operator<<(size_t idx)
{
/*
const auto num_digits = static_cast<unsigned>(log10(double(idx))) + 1;
char body[num_digits+1];
snprintf(body, num_digits+1, "%d", static_cast<int>(idx));
append(body);
*/
*this += to_string(idx);
return *this;
}
@ -225,6 +279,10 @@ String String::operator+(const String& str) const
String& String::operator+=(char c)
{
if (m_data.empty())
{
m_data.push_back('\0');
}
m_data.push_back('\0');
m_data[m_data.size()-2] = c;
return *this;

View file

@ -14,6 +14,10 @@ public:
String(const char* data);
static String fmt(const char* fmt, ...);
void append(const Vector<Byte>& data);
const Vector<char>& data() const;
bool empty() const;
@ -36,10 +40,19 @@ public:
char operator[](std::size_t idx) const;
String& operator<<(const String& body);
String& operator<<(const char* body);
String& operator<<(size_t idx);
template<typename T>
String& operator<<(const T& stringable)
{
*this += stringable.str();
return *this;
}
String& operator+=(const String& str);
String& operator+=(char c);
@ -51,9 +64,9 @@ public:
bool operator!=(const String& other) const;
private:
void append(const Vector<Byte>& data);
void append(const char* data);
Vector<char> m_data;
};
using _s = String;

View file

@ -12,7 +12,6 @@ public:
Vector(std::size_t size)
{
resize(size);
m_size = size;
}
Vector(const Vector& v)
@ -56,22 +55,20 @@ public:
{
v.m_data[idx] = m_data[idx];
}
v.m_size = slice_idx;
return true;
}
bool slice(std::size_t slice_start, std::size_t slice_end, Vector& v) const
{
if (slice_end >= m_size)
if (slice_end > m_size)
{
return false;
}
v.resize(slice_end - slice_start);
for(std::size_t idx=slice_start; idx<slice_end;idx++)
{
v.m_data[idx] = m_data[idx];
v.m_data[idx - slice_start] = m_data[idx];
}
v.m_size = slice_end;
return true;
}
@ -90,36 +87,46 @@ public:
return m_size == 0;
}
void clear()
void clear(bool update_sizes=true)
{
if (has_allocated())
{
m_allocator.delete_array(m_data);
m_data = nullptr;
if (update_sizes)
{
m_capacity = 0;
m_size = 0;
}
}
}
void resize(std::size_t size)
{
resize_capacity(size);
m_size = size;
}
void resize(std::size_t size, const T& value)
{
resize_capacity(size);
m_size = size;
fill_with(value);
}
void extend(const Vector& other)
{
resize(m_size + other.m_size);
for(std::size_t idx=0;idx<other.m_size;idx++)
size_t resize_delta{0};
if (other.m_size > remaining_capacity())
{
resize_delta = other.m_size - remaining_capacity();
resize_capacity(m_capacity + resize_delta);
}
for(size_t idx=0;idx<other.m_size;idx++)
{
m_data[idx + m_size] = other[idx];
}
m_size = m_size + other.m_size;
m_size += other.m_size;
}
T pop_back()
@ -162,7 +169,6 @@ public:
{
m_data[idx] = v.m_data[idx];
}
m_size = v.size();
return *this;
}
@ -196,6 +202,11 @@ private:
return m_capacity > 0;
}
size_t remaining_capacity() const
{
return m_capacity - m_size;
}
void resize_capacity(std::size_t new_capacity)
{
if (!has_allocated())
@ -206,23 +217,18 @@ private:
else if (new_capacity != m_capacity)
{
auto temp = m_allocator.alloc_array(new_capacity);
for(std::size_t idx=0; idx<new_capacity; idx++)
auto min_capacity = new_capacity;
if (m_capacity < min_capacity)
{
min_capacity = m_capacity;
}
for(size_t idx=0; idx<min_capacity; idx++)
{
temp[idx] = m_data[idx];
}
auto old_size = m_size;
clear();
clear(false);
m_data = temp;
m_capacity = new_capacity;
m_size = old_size;
if (old_size > m_capacity)
{
m_size = m_capacity;
}
}
else if(m_size != m_capacity)
{
m_size = m_capacity;
}
}

View file

@ -1,94 +0,0 @@
#include "Directory.h"
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
Vector<FileSystemPath> Directory::getSubdirectories(const FileSystemPath& path)
{
Vector<FileSystemPath> ret;
auto dirp = ::opendir(path.as_string().raw());
while(auto ep = ::readdir(dirp))
{
auto rel_path = String(ep->d_name);
if (rel_path == "." || rel_path == "..")
{
continue;
}
auto full_path = path.join(rel_path);
struct stat sb;
auto rc = lstat(full_path.as_string().raw(), &sb);
if (rc == -1)
{
printf("Got error");
}
if (S_ISDIR(sb.st_mode))
{
printf("Adding full path: %s\n", full_path.as_string().raw());
ret.push_back(full_path);
}
}
::closedir(dirp);
return ret;
}
Vector<FileSystemPath> Directory::getFiles(const FileSystemPath& path, bool recursive)
{
Vector<FileSystemPath> paths;
if (path.is_directory())
{
for (const auto& entry : getSubdirectories(path))
{
if (entry.is_regular_file())
{
paths.push_back(entry);
}
else if(recursive && entry.is_directory())
{
const auto child_paths = getFiles(entry, recursive);
paths.extend(child_paths);
}
}
}
return paths;
}
Vector<FileSystemPath> Directory::getFilesWithExtension(const FileSystemPath& path, const String& extension, bool recursive)
{
Vector<FileSystemPath> paths;
if (path.is_directory())
{
for (const auto& entry : getSubdirectories(path))
{
if (entry.is_regular_file() && entry.extension() == extension)
{
paths.push_back(entry);
}
else if(recursive && entry.is_directory())
{
const auto child_paths = getFilesWithExtension(entry, extension, recursive);
paths.extend(child_paths);
}
}
}
return paths;
}
void Directory::create(const FileSystemPath& path, bool existsOk)
{
(void)existsOk;
FileSystemPath working_path;
if (path.is_directory())
{
working_path = path;
}
else
{
working_path = path.parent_path();
}
if (!working_path.exists())
{
//std::filesystem::create_directories(working_path);
}
}

View file

@ -1,16 +0,0 @@
#pragma once
#include "Vector.h"
#include "FileSystemPath.h"
class Directory
{
public:
static Vector<FileSystemPath> getSubdirectories(const FileSystemPath& path);
static void create(const FileSystemPath& path, bool existsOK = false);
static Vector<FileSystemPath> getFiles(const FileSystemPath& path, bool recursive=false);
static Vector<FileSystemPath> getFilesWithExtension(const FileSystemPath& path, const String& extension, bool recursive=false);
};

View file

@ -0,0 +1,128 @@
#include "Directory.h"
#include "ConsoleLogger.h"
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
Status Directory::getDirectoryContents(const FileSystemPath& path, Vector<FileSystemPath>& ret)
{
Status status;
errno = 0;
auto dirp = ::opendir(path.str().raw());
if (dirp == nullptr)
{
ON_ERRNO("Failed to get directory content in opendir");
}
while(auto ep = ::readdir(dirp))
{
auto rel_path = String(ep->d_name);
if (rel_path == "." || rel_path == "..")
{
continue;
}
const auto full_path = path.join(rel_path);
IF_OK_AND_TRUE(full_path.is_regular_file_or_directory())
{
ret.push_back(full_path);
}
}
String errno_msg;
if (errno != 0)
{
errno_msg = "Failed traversing dirp structure | ";
errno_msg += Error::from_errno();
}
errno = 0;
const auto rc = ::closedir(dirp);
if (rc != 0)
{
errno_msg += "Failed to close dirp";
errno_msg += Error::from_errno();
}
if (!errno_msg.empty())
{
return Status(errno_msg);
}
return {};
}
Status Directory::getFiles(const FileSystemPath& path,
Vector<FileSystemPath>& ret,
bool recursive,
const String& extension)
{
const auto is_dir = path.is_directory();
if (!is_dir.ok())
{
return Status(is_dir.error());
}
if (!is_dir.value())
{
return {};
}
Vector<FileSystemPath> dir_contents;
STATUS_CHECK(getDirectoryContents(path, dir_contents),
"Failed to get directory contents");
for (const auto& entry : dir_contents)
{
IF_OK_AND_TRUE(entry.is_regular_file())
{
if (!extension.empty())
{
if (entry.extension() == extension)
{
ret.push_back(entry);
}
}
else
{
LOG_INFO("Adding entry " << entry);
ret.push_back(entry);
}
}
else if(recursive)
{
IF_OK_AND_TRUE(entry.is_directory())
{
Vector<FileSystemPath> child_paths;
STATUS_CHECK(getFiles(entry, child_paths, recursive), "Failed to get files");
ret.extend(child_paths);
}
}
}
return {};
}
Status Directory::getFilesWithExtension(const FileSystemPath& path,
const String& extension,
Vector<FileSystemPath>& ret,
bool recursive)
{
return getFiles(path, ret, recursive, extension);
}
Status Directory::create(const FileSystemPath& path, bool existsOk)
{
(void)existsOk;
FileSystemPath working_path;
if (path.is_directory().value())
{
working_path = path;
}
else
{
working_path = path.parent_path();
}
if (!working_path.exists())
{
//std::filesystem::create_directories(working_path);
}
return {};
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "Vector.h"
#include "FileSystemPath.h"
#include "Result.h"
class Directory
{
public:
static Status getDirectoryContents(const FileSystemPath& path,
Vector<FileSystemPath>& content);
static Status create(const FileSystemPath& path, bool existsOK = false);
static Status getFiles(const FileSystemPath& path,
Vector<FileSystemPath>& content,
bool recursive=false,
const String& extension = {});
static Status getFilesWithExtension(const FileSystemPath& path,
const String& extension,
Vector<FileSystemPath>& content,
bool recursive=false);
};

View file

@ -16,7 +16,7 @@
class FileImpl
{
public:
void do_open(const FileSystemPath& path, File::AccessMode accessMode)
Status do_open(const FileSystemPath& path, File::AccessMode accessMode)
{
int flags{0};
if (accessMode == File::AccessMode::Read)
@ -28,8 +28,15 @@ public:
flags |= O_WRONLY;
flags |= O_CREAT;
}
errno = 0;
m_fd = ::open(path.str().raw(), flags);
if (m_fd < 0)
{
Status ret;
ret.on_errno("Failed to open file with");
return ret;
}
m_fd = ::open(path.as_string().raw(), flags);
if (accessMode == File::AccessMode::Read)
{
m_open_for_read = true;
@ -38,13 +45,22 @@ public:
{
m_open_for_write = true;
}
return {};
}
void do_close()
Status do_close()
{
::close(m_fd);
errno = 0;
const auto rc = ::close(m_fd);
if (rc < 0)
{
Status ret;
ret.on_errno("Failed to close file with");
return ret;
}
m_open_for_read = false;
m_open_for_write = false;
return {};
}
bool is_ok() const
@ -68,35 +84,56 @@ public:
const auto rc = ::read(m_fd, bytes.data(), bytes.capacity());
if (rc < 0)
{
const auto last_err = errno;
String msg(::strerror(last_err));
const auto msg = _s("Error in read impl | ") + Error::from_errno();
return Result<std::size_t>(Error(msg));
}
return Result<std::size_t>(rc);
}
std::size_t do_write(const VecBytes& bytes)
Result<std::size_t> do_write(const VecBytes& bytes)
{
return ::write(m_fd, bytes.data(), bytes.size());
errno = 0;
const auto rc = ::write(m_fd, bytes.data(), bytes.size());
if (rc < 0)
{
const auto msg = _s("Error in write impl | ") + Error::from_errno();
return Result<std::size_t>(Error(msg));
}
return Result<std::size_t>(rc);
}
std::size_t do_write(const Vector<char>& bytes, int size = -1)
Result<std::size_t> do_write(const Vector<char>& bytes, int size = -1)
{
errno = 0;
int rc = 0;
if (size > -1)
{
return ::write(m_fd, bytes.data(), size);
rc = ::write(m_fd, bytes.data(), size);
}
else
{
return ::write(m_fd, bytes.data(), bytes.size());
rc = ::write(m_fd, bytes.data(), bytes.size());
}
if (rc < 0)
{
const auto msg = _s("Error in write impl | ") + Error::from_errno();
return Result<std::size_t>(Error(msg));
}
return Result<std::size_t>(rc);
}
void update_size()
Status update_size()
{
struct stat buf;
::fstat(m_fd, &buf);
const auto rc = ::fstat(m_fd, &buf);
if (rc != 0)
{
Status ret;
ret.on_errno("Failed to get size with fstat");
return ret;
}
m_size = buf.st_size;
return {};
}
bool m_open_for_write{false};
@ -123,41 +160,77 @@ String File::getExtension() const
return m_path.extension();
}
bool File::readBinary(VecBytes& buffer)
Status File::readBinary(VecBytes& buffer)
{
auto ok = open(AccessMode::Read, true);
if (!ok)
auto status = open(AccessMode::Read, true);
if (!status.ok())
{
return false;
return status;
}
m_impl->update_size();
buffer.resize(m_impl->m_size);
const auto result = m_impl->do_read(buffer);
buffer.resize(result.value());
return true;
status = m_impl->update_size();
if (!status.ok())
{
return status;
}
String File::readText()
{
VecBytes buffer;
auto ok = open(AccessMode::Read, true);
if (!ok)
{
return {};
}
m_impl->update_size();
buffer.resize(m_impl->m_size);
const auto result = m_impl->do_read(buffer);
if (!result.ok())
{
printf("Got error: %s\n", result.error().msg());
return Status(result.error());
}
buffer.resize(result.value());
return {};
}
Status File::readText(String& ret)
{
auto status = open(AccessMode::Read, true);
if (!status.ok())
{
return status;
}
VecBytes buffer;
status = m_impl->update_size();
if (status.ok() && m_impl->m_size > 0)
{
buffer.resize(m_impl->m_size);
const auto result = m_impl->do_read(buffer);
if (!result.ok())
{
return Status(result.error());
}
buffer.resize(result.value());
return String(buffer);
ret.append(buffer);
}
else
{
buffer.resize(1024);
while(true)
{
const auto result = m_impl->do_read(buffer);
if (!result.ok())
{
return Status(result.error());
}
if (result.value() < 1024)
{
if (result.value() > 0)
{
buffer.resize(result.value());
ret.append(buffer);
}
break;
}
else
{
ret.append(buffer);
}
}
}
return {};
}
String File::dumpBinary()
@ -192,7 +265,7 @@ String File::dumpBinary()
Optional<Byte> File::readNextByte()
{
if (!open(AccessMode::Read))
if (!open(AccessMode::Read).ok())
{
return {};
}
@ -216,20 +289,19 @@ Optional<Byte> File::readNextByte()
}
}
bool File::open(AccessMode accessMode, bool binary)
Status File::open(AccessMode accessMode, bool binary)
{
if (m_path.is_absolute() && !m_path.parent_path().exists())
{
Directory::create(m_path.parent_path(), true);
}
m_impl->do_open(m_path, accessMode);
return true;
return m_impl->do_open(m_path, accessMode);
}
void File::close()
Status File::close()
{
m_impl->do_close();
return m_impl->do_close();
}
FileFormat::Format File::inferFormat() const
@ -239,27 +311,34 @@ FileFormat::Format File::inferFormat() const
return {};
}
void File::writeText(const String& text)
Status File::writeText(const String& text)
{
bool had_to_open{false};
Status status;
if (!m_impl->is_open_for_write())
{
had_to_open = true;
m_impl->do_open(m_path, File::AccessMode::Write);
status = m_impl->do_open(m_path, File::AccessMode::Write);
if (!status.ok())
{
return status;
}
}
const auto result = m_impl->do_write(text.data(), text.data().size() - 1);
if (!result.ok())
{
return Status(result.error());
}
m_impl->do_write(text.data(), text.data().size() - 1);
if (had_to_open)
{
m_impl->do_close();
status = m_impl->do_close();
}
return status;
}
Vector<String> File::readLines()
Status File::readLines(Vector<String>& lines)
{
Vector<String> content;
/*
if (!pathExists())
{
@ -279,10 +358,10 @@ Vector<String> File::readLines()
close();
*/
return content;
return {};
}
String File::read()
Status File::read(String& ret)
{
/*
if (!pathExists())
@ -300,11 +379,10 @@ String File::read()
close();
*/
String buffer;
return buffer;
return {};
}
bool File::pathExists() const
bool File::exists() const
{
return m_path.exists();
}

View file

@ -23,7 +23,7 @@ public:
~File();
void close();
Status close();
String dumpBinary();
@ -31,21 +31,21 @@ public:
FileFormat::Format inferFormat() const;
String readText();
Status readText(String& buffer);
Vector<String> readLines();
Status readLines(Vector<String>& lines);
String read();
Status read(String& buffer);
bool pathExists() const;
bool exists() const;
bool open(AccessMode mode, bool binary = false);
Status open(AccessMode mode, bool binary = false);
bool readBinary(VecBytes& bytes);
Status readBinary(VecBytes& bytes);
Optional<Byte> readNextByte();
void writeText(const String& text);
Status writeText(const String& text);
private:
Ptr<FileImpl> m_impl;

View file

@ -4,26 +4,25 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
FileSystemPath::FileSystemPath()
{
}
FileSystemPath::FileSystemPath(const String& path)
: m_path(path)
{
}
const String& FileSystemPath::as_string() const
const String& FileSystemPath::str() const
{
return m_path;
}
Result<bool> FileSystemPath::is_empty() const
{
if (!is_regular_file())
{
return {Error("Requested empty check but target is not regular file.")};
}
ERROR_IF_NOT_OK_OR_TRUE(is_regular_file(),
"Requested empty check but target is not regular file.");
const auto size_result = get_size();
if (!size_result.ok())
{
@ -34,21 +33,24 @@ Result<bool> FileSystemPath::is_empty() const
Result<size_t> FileSystemPath::get_size() const
{
if (!is_regular_file())
{
return {Error("Requested size but target is not regular file.")};
}
ERROR_IF_NOT_OK_OR_TRUE(is_regular_file(),
"Requested size check but target is not regular file.");
struct stat buf;
::stat(m_path.raw(), &buf);
errno = 0;
const auto rc = ::stat(m_path.raw(), &buf);
if (rc != 0)
{
ON_ERRNO_RESULT("Failed to stat file");
}
return buf.st_size;
}
FileSystemPath FileSystemPath::current_dir()
Result<FileSystemPath> FileSystemPath::current_dir()
{
errno = 0;
const auto path_max = ::pathconf(".", _PC_PATH_MAX);
std::size_t size{0};
size_t size{0};
if (path_max == -1)
{
size = 1024;
@ -63,24 +65,48 @@ FileSystemPath FileSystemPath::current_dir()
}
Vector<char> buffer(path_max);
errno = 0;
const auto ret = ::getcwd(buffer.data(), path_max);
if (ret == nullptr)
{
ON_ERRNO_RESULT("Failed to get cwd");
}
return FileSystemPath(String(buffer.data()));
}
bool FileSystemPath::is_regular_file() const
Result<bool> FileSystemPath::is_regular_file() const
{
struct stat path_stat;
::stat(m_path.raw(), &path_stat);
const auto rc = ::stat(m_path.raw(), &path_stat);
if (rc != 0)
{
ON_ERRNO_RESULT("Failed to stat file");
}
return S_ISREG(path_stat.st_mode);
}
bool FileSystemPath::is_directory() const
Result<bool> FileSystemPath::is_directory() const
{
struct stat path_stat;
::stat(m_path.raw(), &path_stat);
const auto rc = ::stat(m_path.raw(), &path_stat);
if (rc != 0)
{
ON_ERRNO_RESULT("Failed to stat file");
}
return S_ISDIR(path_stat.st_mode);
}
Result<bool> FileSystemPath::is_regular_file_or_directory() const
{
struct stat path_stat;
const auto rc = ::stat(m_path.raw(), &path_stat);
if (rc != 0)
{
ON_ERRNO_RESULT("Failed to stat file");
}
return S_ISREG(path_stat.st_mode) || S_ISDIR(path_stat.st_mode);
}
bool FileSystemPath::is_absolute() const
{
return false;
@ -100,6 +126,21 @@ String FileSystemPath::extension() const
return result;
}
String FileSystemPath::file_name() const
{
String name_and_ext;;
const auto split = m_path.rsplit('/');
if (split.second().empty())
{
name_and_ext = split.first();
}
else
{
name_and_ext = split.second();
}
return name_and_ext.rsplit('.').first();
}
bool FileSystemPath::exists() const
{
return ::access(m_path.raw(), F_OK) == 0;

View file

@ -6,16 +6,18 @@
class FileSystemPath
{
public:
FileSystemPath() = default;
FileSystemPath();
FileSystemPath(const String& path);
const String& as_string() const;
const String& str() const;
static FileSystemPath current_dir();
static Result<FileSystemPath> current_dir();
String extension() const;
String file_name() const;
bool exists() const;
Result<bool> is_empty() const;
@ -24,9 +26,11 @@ public:
FileSystemPath join(const String& entry) const;
bool is_regular_file() const;
Result<bool> is_regular_file() const;
bool is_directory() const;
Result<bool> is_directory() const;
Result<bool> is_regular_file_or_directory() const;
bool is_absolute() const;

View file

@ -1,17 +0,0 @@
#include "ConsoleLogger.h"
#include <stdio.h>
#include <stdarg.h>
void ConsoleLogger::logLine(const String& msg)
{
printf("%s\n", msg.raw());
}
void ConsoleLogger::logLine(const char* fmt, ...)
{
va_list(args);
va_start(args, fmt);
vprintf((String(fmt) + "\n").raw(), args);
va_end(args);
}

View file

@ -1,11 +0,0 @@
#pragma once
#include "String.h"
class ConsoleLogger
{
public:
static void logLine(const String& msg);
static void logLine(const char* fmt, ...);
};

View file

@ -0,0 +1,24 @@
#include "ConsoleLogger.h"
#include <stdio.h>
void ConsoleLogger::log_line(Level level,
const String& msg,
const String& fileName,
const String& functionName,
int lineNumber)
{
const auto log_msg = build_log_message(level,
msg,
fileName,
functionName,
lineNumber);
if (level == Level::INFO)
{
printf("%s\n", log_msg.raw());
}
else
{
fprintf(stderr, "%s\n", log_msg.raw());
}
}

View file

@ -0,0 +1,13 @@
#pragma once
#include "Logger.h"
class ConsoleLogger : public Logger
{
public:
void log_line(Level level,
const String& line,
const String& fileName,
const String& functionName,
int lineNumber) override;
};

View file

@ -1,12 +1,5 @@
#pragma once
#define MLOG_ALL(msg, level) {String mt_logstream;\
mt_logstream << msg; \
FileLogger::GetInstance().LogLine(level, mt_logstream, __FILE__, __FUNCTION__, __LINE__);};
#define MLOG_INFO(msg) MLOG_ALL(msg, "Info");
#define MLOG_ERROR(msg) MLOG_ALL(msg, "Error");
#include "Pointer.h"
#include "String.h"

View file

@ -0,0 +1,48 @@
#include "Logger.h"
#include "Time.h"
#include "ConsoleLogger.h"
static Ptr<Logger> s_logger;
Logger* Logger::get_instance()
{
if (s_logger.get() == nullptr)
{
s_logger = Ptr<ConsoleLogger>::create();
}
return s_logger.get();
}
String Logger::build_log_message(Level level,
const String& msg,
const String& fileName,
const String& functionName,
int lineNumber)
{
String log_msg;
if (level == Level::INFO)
{
log_msg += "Info|";
}
else if (level == Level::ERROR)
{
log_msg += "Error|";
}
log_msg += Time::get_now_str() + "|";
String cleaned_filename;
if (auto index = fileName.rindex('/'); index.valid())
{
fileName.slice(index.value()+1, fileName.size(), cleaned_filename);
}
else
{
cleaned_filename = fileName;
}
log_msg += cleaned_filename + "::";
log_msg += functionName + "::";
log_msg += String::to_string(lineNumber) + "|";
log_msg += msg;
return log_msg;
}

View file

@ -0,0 +1,36 @@
#pragma once
#include "String.h"
#include "Pointer.h"
#define LOG_ALL(msg, level) {String mt_logstream;\
mt_logstream << msg; \
Logger::get_instance()->log_line(level, mt_logstream, __FILE__, __FUNCTION__, __LINE__);};
#define LOG_INFO(msg) LOG_ALL(msg, Logger::Level::INFO);
#define LOG_ERROR(msg) LOG_ALL(msg, Logger::Level::ERROR);
class Logger
{
public:
enum class Level
{
INFO,
ERROR
};
virtual ~Logger() = default;
virtual void log_line(Level level,
const String& line,
const String& fileName,
const String& functionName,
int lineNumber){};
static Logger* get_instance();
protected:
static String build_log_message(Level level,
const String& line,
const String& fileName,
const String& functionName,
int lineNumber);
};

View file

@ -12,7 +12,7 @@ public:
return new T;
}
void do_delete(T** p)
void do_delete(T* p)
{
delete p;
}

View file

@ -27,17 +27,28 @@ public:
{
if (m_raw != nullptr)
{
m_allocator.do_delete(&m_raw);
m_allocator.do_delete(m_raw);
}
}
Ptr(const Ptr& other) = delete;
Ptr(Ptr&& other)
: m_allocator(std::move(other.m_allocator)),
m_raw(other.m_raw)
{
other.m_raw = nullptr;
*this = std::move(other);
}
Ptr<T>& operator=(const Ptr<T>& other) = delete;
template<typename U>
Ptr<T>& operator=(Ptr<U>&& other)
{
if (this->m_raw != other.get())
{
this->m_raw = dynamic_cast<T*>(other.get());
other.clear_raw();
}
return *this;
}
T* get()
@ -55,6 +66,11 @@ public:
return m_raw;
}
void clear_raw()
{
m_raw = nullptr;
}
private:
Allocator<T> m_allocator;
T* m_raw{nullptr};

View file

@ -2,7 +2,9 @@
#include "UnicodeUtils.h"
#ifdef _WIN32
#include "Win32BaseIncludes.h"
#endif
CommandLineArgs::CommandLineArgs()
: mArugments(),
@ -46,7 +48,7 @@ FileSystemPath CommandLineArgs::getLaunchPath()
void CommandLineArgs::recordLaunchPath()
{
mLaunchPath = FileSystemPath::current_dir();
mLaunchPath = FileSystemPath::current_dir().value();
}
void CommandLineArgs::process(int argc, char *argv[])

View file

@ -0,0 +1,40 @@
#pragma once
#include "String.h"
#include "File.h"
#include "Result.h"
#include <unistd.h>
class Process
{
public:
Status launch(const String& command)
{
const auto pid = fork();
if (pid < 0)
{
ON_ERRNO("Failed to fork");
}
if (pid == 0)
{
//pass
}
return {};
}
static Result<String> get_self_name()
{
FileSystemPath path(String("/proc/self/cmdline"));
File sys_file(path);
Result<String> ret;
const auto rc = sys_file.readText(ret.value());
if (!rc.ok())
{
ret.on_error(rc.error());
}
return ret;
}
};

View file

@ -0,0 +1,29 @@
#include "Time.h"
#include <time.h>
String Time::get_now_str()
{
time_t time_buf{0};
::time(&time_buf);
if (time_buf == -1)
{
return {};
}
struct tm tm_buf;
auto rc = ::gmtime_r(&time_buf, &tm_buf);
if (rc == nullptr)
{
return {};
}
String ret("T");
ret += String::to_string(tm_buf.tm_mday) + ":";
ret += String::to_string(tm_buf.tm_mon) + ":";
const auto year = (tm_buf.tm_year - 100) + 2000;
ret += String::to_string(year) + "Z";
ret += String::to_string(tm_buf.tm_hour) + ":";
ret += String::to_string(tm_buf.tm_min) + ":";
ret += String::to_string(tm_buf.tm_sec);
return ret;
}

View file

@ -0,0 +1,9 @@
#pragma once
#include "String.h"
class Time
{
public:
static String get_now_str();
};

View file

@ -1,43 +1,16 @@
#include "Vector.h"
#include "String.h"
#include "FileSystemPath.h"
#include "Directory.h"
#include "File.h"
#include "BuildSession.h"
#include "ConsoleLogger.h"
#include <stdio.h>
int main()
int main(int argc, char** argv)
{
/*
FileSystemPath main_path(__FILE__);
printf("Starting build.\n");
auto main_directory = main_path.parent_path();
for(const auto& subdir : Directory::getSubdirectories(main_directory))
if (argc == 1)
{
for(const auto& subsubdir : Directory::getSubdirectories(subdir))
{
const auto build_file = subsubdir.join("build.toml");
if (build_file.exists())
{
printf("Found dir file: %s\n", build_file.as_string().raw());
// Gather all files
//const auto header_files = Directory::getFilesWithExtension(subsubdir, ".h", true);
//for(const auto& header : header_files)
//{
// printf("Found header file: %s\n", header.as_string().raw());
// }
// Gather all directories
// Build library
LOG_ERROR("Missing arg with path to source dir");
return -1;
}
}
}
*/
printf("Finished build.\n");
BuildSession build(argv[1]);
build.scan();
build.build();
return 0;
}

View file

@ -3,21 +3,26 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
CORE_SRC_DIR=$SCRIPT_DIR/../src/base/core
g++ $SCRIPT_DIR/test_runner.cpp \
$SCRIPT_DIR/../src/base/core/CommandLineArgs.cpp \
$CORE_SRC_DIR/system/process/CommandLineArgs.cpp \
$CORE_SRC_DIR/base_types/Error.cpp \
$CORE_SRC_DIR/base_types/Index.cpp \
$CORE_SRC_DIR/data_structures/String.cpp \
$CORE_SRC_DIR/file_utilities/FileSystemPath.cpp \
$CORE_SRC_DIR/loggers/ConsoleLogger.cpp \
$CORE_SRC_DIR/filesystem/FileSystemPath.cpp \
$CORE_SRC_DIR/logging/Logger.cpp \
$CORE_SRC_DIR/logging/ConsoleLogger.cpp \
$CORE_SRC_DIR/time/Time.cpp \
$SCRIPT_DIR/test_utils/TestCaseRunner.cpp \
$SCRIPT_DIR/core/TestFileSystemPath.cpp \
$SCRIPT_DIR/core/TestString.cpp \
$SCRIPT_DIR/core/TestVector.cpp \
-o bootstrap_tests -g \
-o test_runner -g \
-I$SCRIPT_DIR/test_utils \
-I$CORE_SRC_DIR \
-I$CORE_SRC_DIR/encoding \
-I$CORE_SRC_DIR/loggers \
-I$CORE_SRC_DIR/logging \
-I$CORE_SRC_DIR/data_structures \
-I$CORE_SRC_DIR/base_types \
-I$CORE_SRC_DIR/memory \
-I$CORE_SRC_DIR/file_utilities
-I$CORE_SRC_DIR/time \
-I$CORE_SRC_DIR/system/process \
-I$CORE_SRC_DIR/filesystem

View file

@ -0,0 +1,18 @@
#include "FileSystemPath.h"
#include "TestFramework.h"
//#include "TestUtils.h"
#include <iostream>
TEST_CASE(FileSystemPath_Join, "core")
{
FileSystemPath path("/home/jgrogan/code/compilz/src/src");
auto new_path = path.join("test");
REQUIRE(new_path.str() == "/home/jgrogan/code/compilz/src/src/test");
}
TEST_CASE(FileSystemPath_Extension, "core")
{
FileSystemPath path("test.dat");
REQUIRE(path.extension() == ".dat");
}

View file

@ -4,7 +4,7 @@
//#include "TestUtils.h"
#include <iostream>
TEST_CASE(TestBasicStringOps, "core")
TEST_CASE(String_Append, "core")
{
String str;
str += 'a';
@ -12,9 +12,10 @@ TEST_CASE(TestBasicStringOps, "core")
str += 'c';
str += 'd';
REQUIRE(str == "abcd");
String long_string("abc/def/ghi/jkl");
}
TEST_CASE(TestStringReverse, "core")
TEST_CASE(String_Reverse, "core")
{
String str0;
str0.reverse();
@ -37,6 +38,35 @@ TEST_CASE(TestStringReverse, "core")
REQUIRE(str4 == "dcba");
}
TEST_CASE(String_Extend, "core")
{
String str("/home/jgrogan/code/compilz/src/src");
auto str_cpy = str;
str += "/";
str += "test";
REQUIRE(str == String("/home/jgrogan/code/compilz/src/src/test"));
str_cpy += "/";
str_cpy += "test";
REQUIRE(str == str_cpy);
}
TEST_CASE(String_Slice, "core")
{
String str("test.dat");
const auto rindex = str.rindex('.');
REQUIRE(rindex.valid());
REQUIRE(rindex.value() == 4);
String right;
str.slice(rindex.value(), str.size(), right);
REQUIRE(right == ".dat");
const auto split = str.rsplit('.');
REQUIRE(split.first() == "test");
REQUIRE(split.second() == "dat");
}
/*
TEST_CASE(TestStringUtils_StripSurroundingWhitepsace, "core")
{

View file

@ -4,15 +4,38 @@
#include <stdio.h>
TEST_CASE(TestVectorOps, "core")
TEST_CASE(TestVectorExtend, "core")
{
Vector<size_t> vec;
for(size_t idx=0;idx<100;idx++)
for(size_t idx=0; idx<16; idx++)
{
vec.push_back(idx);
}
for(size_t idx=0; idx<100; idx++)
REQUIRE(vec.size() == 16);
Vector<size_t> vec0;
for(size_t idx=16; idx<19; idx++)
{
REQUIRE(vec[idx] == idx);
vec0.push_back(idx);
}
vec.extend(vec0);
REQUIRE(vec.size() == 19);
}
TEST_CASE(TestVectorSlize, "core")
{
Vector<size_t> vec;
for(size_t idx=0; idx<8; idx++)
{
vec.push_back(idx);
}
Vector<size_t> bottom_half;
vec.slice(4, bottom_half);
REQUIRE(bottom_half.size() == 4);
Vector<size_t> top_half;
vec.slice(4, 8, top_half);
REQUIRE(top_half.size() == 4);
}

View file

@ -1,7 +1,7 @@
#include "TestFramework.h"
#include "CommandLineArgs.h"
#include "ConsoleLogger.h"
#include "Logger.h"
#ifdef _WIN32
#include <windows.h>
@ -17,9 +17,9 @@ int main(int argc, char *argv[])
CommandLineArgs args;
args.process(argc, argv);
ConsoleLogger::logLine("Starting test run.");
LOG_INFO("Starting test run.");
TestCaseRunner::getInstance().run(args.getUserArgs());
ConsoleLogger::logLine("Finished test run.");
LOG_INFO("Finished test run.");
#ifdef _WIN32
CoUninitialize();

View file

@ -1,7 +1,7 @@
#include "TestCaseRunner.h"
#include "FileLogger.h"
#include "ConsoleLogger.h"
#include "Logger.h"
//#include "TestUiApplication.h"
bool TestCaseRunner::sLastTestFailed = false;
@ -66,22 +66,22 @@ bool TestCaseRunner::run(const Vector<String>& args)
}
sLastTestFailed = false;
ConsoleLogger::logLine("TestFramework: Running Test - %s", test_case->getName().raw());
LOG_INFO("TestFramework: Running Test - " << test_case->getName());
test_case->run();
if (sLastTestFailed)
{
ConsoleLogger::logLine("Failed at line %s", sFailureLine.raw());
LOG_INFO("Failed at line: " << sFailureLine);
mFailingTests.push_back(test_case->getName());
}
}
if (mFailingTests.size() > 0)
{
ConsoleLogger::logLine("%d failing tests", mFailingTests.size());
LOG_INFO(String::fmt("%d failing tests", mFailingTests.size()));
for(const auto& name : mFailingTests)
{
ConsoleLogger::logLine(name);
LOG_INFO(name);
}
}

View file

@ -21,6 +21,7 @@ struct Holder
{ \
const auto msg = String::to_string(__LINE__) + String(" with check: '") + String(#predicate) + String("'"); \
TestCaseRunner::getInstance().markTestFailure(msg); \
return; \
} \