2019-07-02 03:32:09 +00:00

222 lines
6.6 KiB
Plaintext
Executable File

class cfg {
private import rt::c;
private alias
vector = std::vector,
string = std::string;
struct item {
name string;
value string;
cover char;
}
struct cfg {
items vector<item>;
filename string;
}
func constructor() {
constructor(this);
}
func destructor() {
destructor(this);
}
func open(filename. char) bool {
define {
SIZE_LIMIT = 0x1000000;
}
lambda read(filename. char, file_size& size_t) void [
var stream void = fopen(filename, "rb");
if stream == null;
return null;
defer fclose(stream);
if fseek(stream, 0, SEEK_END) < 0;
return null;
var tail long = ftell(stream);
if tail < 0 or tail > SIZE_LIMIT;
return null;
rewind(stream);
func = malloc(tail);
var offset size_t = 0;
var remain size_t = tail;
while remain {
var size size_t = fread(func + offset, 1, remain, stream);
if ferror(stream) {
free(func);
return null;
}
offset += size;
remain -= size;
}
file_size = offset;
];
var size size_t;
var buf. char = read(filename, size);
if buf == null;
return false;
defer free(buf);
this.items->clear();
this.filename->clear();
lambda skip_space(buf. char, index& size_t, size size_t) bool [
for ; index < size; index++ {
if !isspace(buf[index]) {
return true;
}
}
return false;
];
lambda skip_line(buf. char, index& size_t, size size_t, end& size_t) bool [
for ; index < size; index++ {
var c char = buf[index];
if c == '\r' {
end = index;
if ++index < size {
if buf[index] == '\n' {
index++;
return true;
}
else
return false;
}
elseif c == '\n';
end = index++;
return true;
}
}
end = index;
return false;
];
lambda skip_name(buf. char, index& size_t, size size_t) bool [
for ; index < size; index++ {
var c char = buf[index];
if c == ' ' or c == '\t' or c == '\r' or c == '\n' or c == '=' {
return true;
}
}
return false;
];
lambda skip_until(buf. char, index& size_t, size size_t, end char) bool [
for ; index < size; index++ {
if buf[index] == end {
return true;
}
}
return false;
];
forvar index size_t = 0 ;; {
if !skip_space(buf, index, size);
break;
var name_offset size_t = index;
if !skip_name(buf, index, size);
break;
var name_size size_t = index - name_offset;
if !name_size;
return false;
if buf[index] ~= '=' {
if !skip_space(buf, ++index, size);
break;
if buf[index] ~= '=';
return false;
}
if !skip_space(buf, ++index, size);
break;
var value_offset size_t;
var value_size size_t;
var cover char;
if buf[index] == '\'' or
buf[index] == '\"' {
cover = buf[index];
value_offset = ++index;
if !skip_until(buf, index, size, cover);
break;
value_size = index++ - value_offset;
else
value_offset = index;
var end size_t;
skip_line(buf, index, size, end);
value_size = end - value_offset;
cover = 0;
}
var item. item = this.items->new();
item.name->set(buf + name_offset, name_size);
if value_size;
item.value->set(buf + value_offset, value_size);
item.cover = cover;
}
this.filename->set(filename);
return true;
}
func save(filename. char = null) bool {
var stream void;
if filename == null {
if this.filename->empty();
return false;
stream = fopen(this.filename->ptr(), "w");
else
stream = fopen(filename, "w");
}
if stream == null;
return false;
forvar index size_t = 0, count size_t = this.items->count(); index < count; index++ {
var item. item = this.items->at(index);
if item.cover {
fprintf("%s = %c%s%c\n",
item.name->ptr(),
item.cover,
item.value->ptr(),
item.cover);
else
fprintf("%s = %s\n",
item.name->ptr(),
item.value->ptr());
}
}
fclose(stream);
}
func find(name. char) .item {
var count size_t = this.items->count();
while count {
var item. item = this.items->at(--count);
if !strcasecmp(item.name->ptr(), name) {
return item;
}
}
return null;
}
func get(name. char) .char {
var item. item = this->find(name);
if item == null;
return null;
return item.value->ptr();
}
func set(name. char, value. char) bool {
var item. item = this->find(name);
if item == null;
return false;
item.value->set(value);
return true;
}
func add(name. char, value. char = null, cover char = '"') bool {
var item. item = this->find(name);
if item ~= null;
return false;
item = this.items->new();
item.name->set(name);
if value ~= null;
item.value->set(value);
item.cover = cover;
return true;
}
}