/* PIP - Platform Independent Primitives Config parser Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "piconfig.h" PIConfig::Entry PIConfig::Branch::_empty; PIConfig::Entry PIConfig::Entry::_empty; PIConfig::Branch PIConfig::Branch::allLeaves() { Branch b; b.delim = delim; piForeach (Entry * i, *this) { if (i->isLeaf()) b << i; else allLeaves(b, i); } return b; } PIConfig::Entry & PIConfig::Branch::getValue(const PIString & vname, const PIString & def, bool * exist) { if (vname.isEmpty()) { _empty.clear(); _empty.delim = delim; if (exist != 0) *exist = false; return _empty; } PIStringList tree = vname.split(delim); PIString name = tree.front(); tree.pop_front(); Entry * ce = 0; piForeach (Entry * i, *this) if (i->_name == name) { ce = i; break; } if (ce == 0) { _empty._name = vname; _empty._value = def; _empty.delim = delim; if (exist != 0) *exist = false; return _empty; } piForeach (PIString & i, tree) { ce = ce->findChild(i); if (ce == 0) { _empty._name = vname; _empty._value = def; _empty.delim = delim; if (exist != 0) *exist = false; return _empty; } } if (exist != 0) *exist = true; return *ce; } PIConfig::Branch PIConfig::Branch::getValues(const PIString & name) { Branch b; b.delim = delim; piForeach (Entry * i, *this) { if (i->isLeaf()) { if (i->_name.find(name) >= 0) b << i; } else { piForeach (Entry * j, i->_children) if (j->_name.find(name) >= 0) b << j; } } return b; } PIConfig::Branch PIConfig::Branch::getLeaves() { Branch b; b.delim = delim; piForeach (Entry * i, *this) if (i->isLeaf()) b << i; return b; } PIConfig::Branch PIConfig::Branch::getBranches() { Branch b; b.delim = delim; piForeach (Entry * i, *this) if (!i->isLeaf()) b << i; return b; } PIConfig::Branch & PIConfig::Branch::filter(const PIString & f) { for (int i = 0; i < size_s(); ++i) { if (at(i)->_name.find(f) < 0) { remove(i); --i; } } return *this; } bool PIConfig::Branch::entryExists(const Entry * e, const PIString & name) const { if (e->_children.isEmpty()) { if (e->_name == name) return true; else return false; } piForeachC (Entry * i, e->_children) if (entryExists(i, name)) return true; return false; } PIConfig::Entry & PIConfig::Entry::getValue(const PIString & vname, const PIString & def, bool * exist) { PIStringList tree = vname.split(delim); Entry * ce = this; piForeach (PIString & i, tree) { ce = ce->findChild(i); if (ce == 0) { _empty._name = vname; _empty._value = def; _empty.delim = delim; if (exist != 0) *exist = false; return _empty; } } if (exist != 0) *exist = true; return *ce; } PIConfig::Branch PIConfig::Entry::getValues(const PIString & vname) { Branch b; b.delim = delim; piForeach (Entry * i, _children) if (i->_name.find(vname) >= 0) b << i; return b; }; bool PIConfig::Entry::entryExists(const Entry * e, const PIString & name) const { if (e->_children.isEmpty()) { if (e->_name == name) return true; else return false; } piForeachC (Entry * i, e->_children) if (entryExists(i, name)) return true; return false; } PIConfig::PIConfig(const PIString & path, PIIODevice::DeviceMode mode): PIFile(path, mode) { delim = "."; root.delim = delim; empty.delim = delim; empty._parent = 0; if (!isOpened()) open(path, mode); parse(); } PIConfig::Entry & PIConfig::getValue(const PIString & vname, const PIString & def, bool * exist) { PIStringList tree = vname.split(delim); Entry * ce = &root; piForeach (PIString & i, tree) { ce = ce->findChild(i); if (ce == 0) { if (exist != 0) *exist = false; empty._name = vname; empty._value = def; empty.delim = delim; return empty; } } if (exist != 0) *exist = true; return *ce; } PIConfig::Branch PIConfig::getValues(const PIString & vname) { Branch b; b.delim = delim; piForeach (Entry * i, root._children) if (i->_name.find(vname) >= 0) b << i; return b; }; void PIConfig::addEntry(const PIString & name, const PIString & value, const PIString & type, bool write) { if (getValue(name)._parent != 0) return; bool toRoot = false; PIStringList tree = name.split(delim); PIString ename = tree.back(); tree.pop_back(); Entry * te, * ce, * entry = &root; if (tree.isEmpty()) toRoot = true; piForeach (PIString & i, tree) { te = entry->findChild(i); if (te == 0) { ce = new Entry(); ce->delim = delim; ce->_tab = entry->_tab; ce->_line = entry->_line; ce->_name = i; ce->_parent = entry; entry->_children << ce; entry = ce; } else entry = te; } PIConfig::Branch ch = entry->_children; ch.sort(PIConfig::Entry::compare); te = (entry->isLeaf() ? 0 : ch.back()); ce = new Entry(); ce->delim = delim; ce->_name = ename; ce->_value = value; ce->_type = type; if (te == 0) { ce->_tab = entry->_tab; if (toRoot) ce->_line = other.size_s() - 1; else ce->_line = entry->_line; } else { ce->_tab = te->_tab; if (toRoot) ce->_line = other.size_s() - 1; else { ch = entry->_parent->_children; ch.sort(PIConfig::Entry::compare); ce->_line = ch.back()->_line + 1; } } ce->_parent = entry; entry->_children << ce; other.insert(ce->_line, ""); Branch b = allLeaves(); bool found = false; for (int i = 0; i < b.size_s(); ++i) { if (found) { b[i]->_line++; continue; } if (b[i] == ce) { found = true; if (i > 0) if (b[i - 1]->_line == b[i]->_line) b[i - 1]->_line++; } } if (write) writeAll(); } void PIConfig::setValue(const PIString & name, const PIString & value, const PIString & type, bool write) { Entry & e(getValue(name)); if (&e == &empty) { addEntry(name, value, type); return; } e._value = value; e._type = type; if (write) writeAll(); } int PIConfig::entryIndex(const PIString & name) { PIStringList tree = name.split(delim); Entry * ce = &root; piForeach (PIString & i, tree) { ce = ce->findChild(i); if (ce == 0) return -1; } Branch b = allLeaves(); return allLeaves().indexOf(ce); } void PIConfig::setValue(uint number, const PIString & value, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; e._value = value; if (write) writeAll(); } void PIConfig::setName(uint number, const PIString & name, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; e._name = name; if (write) writeAll(); } void PIConfig::setType(uint number, const PIString & type, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; e._type = type; if (write) writeAll(); } void PIConfig::setComment(uint number, const PIString & comment, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; e._comment = comment; if (write) writeAll(); } void PIConfig::removeEntry(const PIString & name, bool write) { Entry & e(getValue(name)); if (&e == &empty) return; Branch b = allLeaves(); removeEntry(b, &e); if (write) writeAll(); } void PIConfig::removeEntry(uint number, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; Branch b = allLeaves(); removeEntry(b, &e); if (write) writeAll(); } void PIConfig::removeEntry(Branch & b, PIConfig::Entry * e) { bool leaf = true; if (e->isLeaf()) other.remove(e->_line); if (!e->isLeaf() && !e->_value.isEmpty()) { e->_value.clear(); leaf = false; } else { int cc = e->_children.size_s(); piForTimes (cc) removeEntry(b, e->_children.back()); } bool found = false; for (int i = 0; i < b.size_s(); ++i) { if (found) { b[i]->_line--; continue; } if (b[i] == e) found = true; } if (!leaf) return; e->_parent->_children.removeOne(e); b.removeOne(e); delete e; } void PIConfig::writeAll() { clear(); //writeEntry(&root); buildFullNames(&root); Branch b = allLeaves(); int j = 0; for (int i = 0; i < other.size_s(); ++i) { //cout << j << endl; if (j >= 0 && j < b.size_s()) { if (b[j]->_line == i) { b[j]->buildLine(); *this << b[j]->_all << '\n'; ++j; } else { *this << other[i]; if (i < other.size_s() - 1) *this << '\n'; } } else { *this << other[i]; if (i < other.size_s() - 1) *this << '\n'; } } flush(); readAll(); } void PIConfig::readAll() { root.clear(); flush(); parse(); } bool PIConfig::entryExists(const Entry * e, const PIString & name) const { if (e->_children.isEmpty()) { if (e->_name == name) return true; else return false; } piForeachC (Entry * i, e->_children) if (entryExists(i, name)) return true; return false; } void PIConfig::parse() { PIString src, str, tab, comm, all, name, type; PIStringList tree; Entry * entry, * te, * ce; int ind, sind; bool isNew; if (!isOpened()) return; seekToBegin(); other.clear(); lines = centry = 0; while (!isEnd()) { other.push_back(PIString()); src = str = readLine(); //cout << str << endl; tab = str.left(str.find(str.trimmed().left(1))); str.trim(); all = str; ind = str.find('='); if ((ind > 0) && !(str[0] == '#')) { sind = str.find('#'); if (sind > 0) { comm = str.right(str.length() - sind - 1).trimmed(); if (comm.length() > 0) type = comm[0]; else type = "s"; comm = comm.right(comm.length() - 1).trimmed(); str = str.left(sind); } else { type = "s"; comm = ""; } //name = str.left(ind).trimmed(); tree = str.left(ind).trimmed().split(delim); name = tree.back(); tree.pop_back(); entry = &root; piForeach (PIString & i, tree) { te = entry->findChild(i); if (te == 0) { ce = new Entry(); ce->delim = delim; ce->_tab = tab; ce->_line = lines; ce->_name = i; ce->_parent = entry; entry->_children << ce; entry = ce; } else entry = te; } isNew = false; ce = entry->findChild(name); if (ce == 0) { ce = new Entry(); isNew = true; } ce->delim = delim; ce->_tab = tab; ce->_name = name; ce->_value = str.right(str.length() - ind - 1).trimmed(); ce->_type = type; ce->_comment = comm; ce->_line = lines; ce->_all = all; if (isNew) { ce->_parent = entry; entry->_children << ce; } } else other.back() = src; lines++; } setEntryDelim(&root, delim); buildFullNames(&root); }