New File tools
This commit is contained in:
@@ -5,10 +5,27 @@
|
||||
|
||||
#include "DawnTool.hpp"
|
||||
|
||||
#if !defined(DAWN_TOOL_INSTANCE)
|
||||
#error Dawn Tool Instance, e.g. LanguageTool has not been defined
|
||||
#endif
|
||||
|
||||
#if !defined(DAWN_TOOL_HEADER)
|
||||
#error Dawn Tool Include, e.g. LanguageTool.hpp has not been defined
|
||||
#endif
|
||||
|
||||
#include DAWN_TOOL_HEADER
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
DawnTool::DawnTool(const int argc, const char *argv[]) {
|
||||
int32_t DawnTool::exec(const int32_t argc, const char *argv[]) {
|
||||
for(int32_t i = 0; i < argc; i++) {
|
||||
this->args.push_back(std::string(argv[i]));
|
||||
}
|
||||
|
||||
return this->start();
|
||||
}
|
||||
|
||||
int main(const int32_t argc, const char *argv[]) {
|
||||
DAWN_TOOL_INSTANCE self;
|
||||
return self.exec(argc, argv);
|
||||
}
|
@@ -20,8 +20,9 @@ namespace Dawn {
|
||||
std::vector<std::string> args;
|
||||
|
||||
public:
|
||||
DawnTool(const int argc, const char *argv[]);
|
||||
|
||||
int32_t exec(const int32_t argc, const char *argv[]);
|
||||
virtual int32_t start() = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
int main(const int32_t argc, const char *argv[]);
|
108
src/dawntools/util/File.hpp
Normal file
108
src/dawntools/util/File.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "assert/assert.hpp"
|
||||
#include "util/file.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
#define FILE_BUFFER_SIZE 512
|
||||
|
||||
namespace Dawn {
|
||||
enum FileMode {
|
||||
FILE_MODE_READ,
|
||||
FILE_MODE_WRITE
|
||||
};
|
||||
|
||||
class File {
|
||||
private:
|
||||
FILE *file = nullptr;
|
||||
enum FileMode mode;
|
||||
size_t length;
|
||||
|
||||
public:
|
||||
std::string filename;
|
||||
|
||||
File(std::string filename) {
|
||||
this->filename = fileNormalizeSlashesNew(filename);
|
||||
}
|
||||
|
||||
bool_t open(enum FileMode mode) {
|
||||
assertNull(this->file);
|
||||
|
||||
this->mode = mode;
|
||||
this->file = fopen(
|
||||
this->filename.c_str(),
|
||||
mode == FILE_MODE_READ ? "rb" : "wb"
|
||||
);
|
||||
|
||||
if(this->file == NULL) return false;
|
||||
|
||||
fseek(this->file, 0, SEEK_END);
|
||||
this->length = ftell(this->file);
|
||||
fseek(this->file, 0, SEEK_SET);
|
||||
|
||||
if(this->length <= 0) {
|
||||
this->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool_t isOpen() {
|
||||
return this->file != nullptr;
|
||||
}
|
||||
|
||||
void close() {
|
||||
assertNotNull(this->file);
|
||||
fclose(this->file);
|
||||
}
|
||||
|
||||
bool_t readString(std::string *out) {
|
||||
assertNotNull(out);
|
||||
|
||||
if(!this->isOpen()) {
|
||||
if(!this->open(FILE_MODE_READ)) return false;
|
||||
}
|
||||
assertTrue(this->mode == FILE_MODE_READ);
|
||||
out->clear();
|
||||
|
||||
size_t i = 0;
|
||||
char buffer[FILE_BUFFER_SIZE + 1];
|
||||
while(i != this->length) {
|
||||
size_t amt = mathMin<size_t>(FILE_BUFFER_SIZE, (this->length - i));
|
||||
auto amtRead = fread(buffer, sizeof(char), amt, this->file);
|
||||
if(amtRead != amt) return false;
|
||||
i += amtRead;
|
||||
buffer[amtRead + 1] = '\0';
|
||||
out->append(buffer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool_t mkdirp() {
|
||||
fileMkdirp((char *)this->filename.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool_t writeString(std::string in) {
|
||||
if(!this->isOpen()) {
|
||||
if(!this->open(FILE_MODE_WRITE)) return false;
|
||||
}
|
||||
assertTrue(this->mode == FILE_MODE_WRITE);
|
||||
|
||||
const char_t *strOut = in.c_str();
|
||||
// TODO: Validate write length.
|
||||
fwrite(strOut, sizeof(char_t), in.size(), this->file);
|
||||
return true;
|
||||
}
|
||||
|
||||
~File() {
|
||||
if(this->file != nullptr) this->close();
|
||||
}
|
||||
};
|
||||
}
|
@@ -1,223 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "XmlNew.hpp"
|
||||
#include "util/array.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
bool_t Xml::isWhitespace(char_t c) {
|
||||
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
|
||||
}
|
||||
|
||||
Xml Xml::load(std::string data) {
|
||||
size_t j = 0;
|
||||
Xml xml;
|
||||
Xml::load(&xml, data, &j);
|
||||
return xml;
|
||||
}
|
||||
|
||||
void Xml::load(Xml *xml, std::string data, size_t *j) {
|
||||
char_t c;
|
||||
int32_t level = 0;
|
||||
enum XmlParseState doing = XML_PARSE_STATE_DOING_NOTHING;
|
||||
enum XmlParseState doingBeforeComment;
|
||||
bool_t insideTag = false;
|
||||
std::string buffer = "";
|
||||
std::string attrKey = "";
|
||||
size_t i = *j;
|
||||
|
||||
while(c = data[i++]) {
|
||||
switch(doing) {
|
||||
case XML_PARSE_STATE_DOING_NOTHING:
|
||||
if(c == '>') continue;
|
||||
if(c == '<') {
|
||||
if(data[i] == '!' && data[i+1] == '-' && data[i+2] == '-') {
|
||||
doingBeforeComment = doing;
|
||||
doing = XML_PARSE_STATE_PARSING_COMMENT;
|
||||
i += 3;
|
||||
} else if(insideTag) {
|
||||
i -= 1;
|
||||
auto child = new Xml();
|
||||
Xml::load(child, data, &i);
|
||||
xml->children.push_back(child);
|
||||
doing = XML_PARSE_STATE_PARSING_CHILD;
|
||||
} else {
|
||||
doing = XML_PARSE_STATE_PARSING_TAG_NAME;
|
||||
level++;
|
||||
insideTag = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(Xml::isWhitespace(c)) continue;
|
||||
doing = XML_PARSE_STATE_PARSING_VALUE;
|
||||
buffer += c;
|
||||
break;
|
||||
|
||||
case XML_PARSE_STATE_PARSING_TAG_NAME:
|
||||
// Just keep reading until we either hit a space (end of the tag name)
|
||||
// or a closing tag value, either / or >
|
||||
if(Xml::isWhitespace(c) || c == '>' || c == '/') {
|
||||
xml->node = buffer;
|
||||
buffer = "";
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSE_STATE_PARSING_CLOSE;
|
||||
} else {
|
||||
doing = c == '>' ? XML_PARSE_STATE_DOING_NOTHING : XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer += c;
|
||||
break;
|
||||
|
||||
|
||||
case XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE:
|
||||
// Look until we hit either the end of a tag, or the attribute itself
|
||||
if(Xml::isWhitespace(c) || c == '>' || c == '/' || c == '=') {
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_PARSE_STATE_DOING_NOTHING;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSE_STATE_PARSING_CLOSE;
|
||||
}
|
||||
} else if(c == '=') {
|
||||
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE;
|
||||
} else {
|
||||
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
|
||||
if(buffer.size() > 0) {
|
||||
attrKey = buffer;
|
||||
xml->attributes[buffer] = "";
|
||||
buffer = "";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer += c;
|
||||
break;
|
||||
|
||||
case XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE:
|
||||
// Keep looking until we find a quote mark
|
||||
if(Xml::isWhitespace(c)) continue;
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_PARSE_STATE_DOING_NOTHING;
|
||||
insideTag = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c != '"') continue;
|
||||
doing = XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE;
|
||||
break;
|
||||
|
||||
case XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE:
|
||||
// Parse the attribute value until we find a quote mark.
|
||||
if(c == '"') {
|
||||
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
|
||||
xml->attributes[attrKey] = buffer;
|
||||
buffer = "";
|
||||
continue;
|
||||
}
|
||||
buffer += c;
|
||||
break;
|
||||
|
||||
case XML_PARSE_STATE_PARSING_VALUE:
|
||||
// Keep parsing child until we find a < for an opening/closing tag.
|
||||
if(c == '<') {
|
||||
// In HTML Spec there could be a child here but not in XML spec.
|
||||
doing = XML_PARSE_STATE_PARSING_CLOSE;
|
||||
xml->value = buffer;
|
||||
buffer = "";
|
||||
continue;
|
||||
}
|
||||
buffer += c;
|
||||
break;
|
||||
|
||||
case XML_PARSE_STATE_PARSING_CHILD:
|
||||
if(c == '<') {
|
||||
// Read ahead and confirm this is a close or not
|
||||
if(data[i] == '/') {
|
||||
doing = XML_PARSE_STATE_PARSING_CLOSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(data[i] == '!' && data[i+1] == '-' && data[i+2] == '-') {
|
||||
doingBeforeComment = doing;
|
||||
doing = XML_PARSE_STATE_PARSING_COMMENT;
|
||||
i += 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Likely another child.
|
||||
auto child = new Xml();
|
||||
i -= 1;
|
||||
Xml::load(child, data, &i);
|
||||
xml->children.push_back(child);
|
||||
}
|
||||
|
||||
if(Xml::isWhitespace(c)) continue;
|
||||
|
||||
// In HTML Spec there's a chance for there to be a value here, but not
|
||||
// in the XML spec.
|
||||
break;
|
||||
|
||||
case XML_PARSE_STATE_PARSING_CLOSE:
|
||||
// Just keep parsing until the tag closer finishes.
|
||||
if(c != '>') continue;
|
||||
doing = XML_PARSE_STATE_DOING_NOTHING;
|
||||
|
||||
//TODO: Return index or something?
|
||||
*j = i;
|
||||
return;
|
||||
|
||||
case XML_PARSE_STATE_PARSING_COMMENT:
|
||||
if(c != '-') continue;
|
||||
if(data[i] != '-') continue;
|
||||
if(data[i+1] != '>') continue;
|
||||
i += 2;
|
||||
doing = doingBeforeComment;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*j = i;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Xml*> Xml::getChildrenOfType(std::string type) {
|
||||
std::vector<Xml*> children;
|
||||
auto itChildren = this->children.begin();
|
||||
while(itChildren != this->children.end()) {
|
||||
auto child = *itChildren;
|
||||
if(child->node == type) children.push_back(child);
|
||||
++itChildren;
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
Xml * Xml::getFirstChildOfType(std::string type) {
|
||||
auto itChildren = this->children.begin();
|
||||
while(itChildren != this->children.end()) {
|
||||
auto child = *itChildren;
|
||||
if(child->node == type) return child;
|
||||
++itChildren;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
Xml::~Xml() {
|
||||
auto it = this->children.begin();
|
||||
while(it != this->children.end()) {
|
||||
delete *it;
|
||||
++it;
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnsharedlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
enum XmlParseState {
|
||||
XML_PARSE_STATE_DOING_NOTHING,
|
||||
XML_PARSE_STATE_PARSING_TAG_NAME,
|
||||
XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE,
|
||||
XML_PARSE_STATE_PARSING_ATTRIBUTE_NAME,
|
||||
XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE,
|
||||
XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE,
|
||||
XML_PARSE_STATE_PARSING_VALUE,
|
||||
XML_PARSE_STATE_PARSING_CHILD,
|
||||
XML_PARSE_STATE_PARSING_CLOSE,
|
||||
XML_PARSE_STATE_PARSING_COMMENT
|
||||
};
|
||||
|
||||
class Xml {
|
||||
protected:
|
||||
static bool_t isWhitespace(char_t c);
|
||||
|
||||
public:
|
||||
static Xml load(std::string data);
|
||||
static void load(Xml *xml, std::string data, size_t *j);
|
||||
|
||||
|
||||
|
||||
std::string node;
|
||||
std::string value;
|
||||
std::map<std::string, std::string> attributes;
|
||||
std::vector<Xml*> children;
|
||||
|
||||
std::vector<Xml*> getChildrenOfType(std::string type);
|
||||
Xml * getFirstChildOfType(std::string type);
|
||||
|
||||
~Xml();
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user