[RFC] ini parser
bioinfornatics
bioinfornatics at fedoraproject.org
Wed Feb 22 03:35:43 PST 2012
I have wrote a ini parser it can use bidirectional range
example of ini file able to parse:
_______________________________________
[sectionA]
param1=value1
param2=value2
[[subSectionA]]
param1sub=value1sub
[sectionB]
param3=value3
; I am a comment
param4=value4
[sectionC]
param5=value5
param6=value6
_______________________________________
Example to code who use ini parser
_______________________________________
import std.string;
import std.stdio;
import std.ini;
void main( ){
writeln( "0 - Starting test" );
IniFile tester = open("myConfig.ini");
writeln( "Ini file loaded" );
writefln( "1 - Name: %s, level: %d", tester.name, tester.level);
writefln( "2 - childs:\n%s,", tester.childs );
writefln( "3 - object is null: %s", tester is null );
writefln( "4 - number of section: %d", tester.length );
writefln( "5 - sectionA: %s", tester.get("sectionA") );
writefln( "6 - sectionA.param1: %s",
tester.get("sectionA")["param1"] );
writefln( "7 - first section:\n%s", tester.front );
writeln( "8 - popfront" );
tester.popFront();
writefln( "9 - first section:\n%s", tester.front );
}
----------------OUTPUT------------------------
0 - Starting test
Ini file loaded
1 - Name: root, level: 0
2 - childs:
[[sectionA]
param1=value1
param2=value2
[[subSectionA]]
param1sub=value1sub
, [sectionB]
param3=value3
param4=value4
, [sectionC]
param5=value5
param6=value6
],
3 - object is null: false
4 - number of section: 3
5 - sectionA: [sectionA]
param1=value1
param2=value2
[[subSectionA]]
param1sub=value1sub
6 - sectionA.param1: value1
7 - first section:
[sectionA]
param1=value1
param2=value2
[[subSectionA]]
param1sub=value1sub
8 - popfront
9 - first section:
[sectionB]
param3=value3
param4=value4
_______________________________________
The code
_______________________________________
module std.ini;
private import std.stream : BufferedFile;
private import std.string : format, stripLeft, stripRight;
private import std.array : split;
private import std.stdio : File;
private import std.stdio : writeln, writefln, writef;
private import std.exception : Exception;
/**
* parse is a method for parse a INI file or config file.
*
* Returns: A Section object with all information
*
* Examples:
* --------------------
* import std.ini;
* string filePath = "~/myGreatSetup.conf";
* Section sections = configFile.open( filePath );
* --------------------
*/
IniFile open( string filePath ){
Section root = new Section("root",
0); // root section
Section currentSection =
root; // reference to current section
Section nextSection = null;
File iniFile = File( filePath, "r" );
foreach( line; iniFile.byLine()
){ // read line by line
try{
line = line.stripLeft().stripRight();
if( line == "" || line[0] == ';'
){ // empty line line or comment line
continue;
}
else if( line[0] == '['
){ // section start
nextSection = getSection( cast(string)line
); // get newest section
if( currentSection.level < nextSection.level
){ // currentSection.level < nextSection.level
currentSection.addChild( nextSection
); // add a child to current section
currentSection =
nextSection; // now current section go to next one
}
else if( currentSection.level == nextSection.level
){ // currentSection.level = nextSection.level
currentSection =
currentSection.rewind( currentSection.parent.level );
currentSection.addChild( nextSection );
currentSection = nextSection;
}
else{ //
currentSection.level > nextSection.level
currentSection =
currentSection.rewind( nextSection.level - 1);
currentSection.addChild( nextSection );
currentSection = nextSection;
}
}
else{ // read
information corresponding to a section
string[] words = split(cast(string)line,
"="); // get key / value peer
foreach( ref string word; words )
word.stripRight().stripLeft(); // remove space,
before and after word
currentSection[ words[0] ] = words[1];
}
}
catch(Exception e){
writeln( "Error: config file seem to not not follow
specification!" );
writeln( e.msg );
writefln( "Line: %s", line );
}
}
root.shrink;
return root;
}
alias Section IniFile;
class Section{
private:
string _name;
Section _parent;
Section[] _childs;
size_t _level;
size_t _numberOfChild;
string[string] _dict;
public:
/**
* Constructor for a Section object
*
* Params: name level
*/
this(string name, size_t level){
this._name = name;
this._level = level;
this._childs = [];
this._numberOfChild = 0;
this._dict = null;
}
/**
* Constructor for copy Section object
*
* Params: name parent level childs numberOfChild dict
*/
this( string name, Section parent, size_t level, Section[]
childs, size_t numberOfChild, string[string] dict ){
this._name = name;
this._level = level;
this._childs.length = childs.length;
foreach(size_t index, child; childs)
this._childs[index] = child.dup;
this._numberOfChild = numberOfChild;
this._dict = dict;
}
/**
* addChild is used for add a subsection to current section
*
* Params: Section
*/
void addChild( ref Section section ){
if( _numberOfChild >= _childs.length )
_childs.length = _childs.length + 5; //
resize +5 for not resize 1 by 1
section.parent = this;
_childs[_numberOfChild] = section;
_numberOfChild++;
}
/**
* Resize object to same size as data contained by the object
*/
@property void shrink(){
_childs.length = _numberOfChild;
foreach( child; _childs )
child.shrink;
}
/**
* get return the subsection where name equal name given
*
* Params: name
*
* Retuns: Section, null if not found
*/
Section get( string name ){
Section section = null;
bool isSearching = true;
size_t index = 0;
while( isSearching ){
if( index >= _numberOfChild )
isSearching = false;
else if( _childs[index].name == name ){
isSearching = false;
section = _childs[index].dup;
}
index++;
}
return section;
}
/**
* opIndex
* Acces to a value in current Section by giving his key
*/
string opIndex( string key ){
return _dict[key];
}
/**
* opIndexAssign
* Append a pair key/value in current Section
*/
void opIndexAssign( string value, string key ){
_dict[key.idup] = value.idup;
}
/**
* rewind is used for come back to parent at level given
*
* Params: level
*/
Section rewind( size_t levelToGo
){ // rewind to parent level x
Section section = null;
if( _level == levelToGo)
section = this;
else if( _level >= levelToGo)
section = _parent.rewind( levelToGo );
else
throw new Exception("You try to go back when current
section is lower where level you want to go!");
return section;
}
/**
* toString used for print current object state
*
* Returns: a string
*/
override string toString(){
string content = "";
string start = "";
string end = "";
if( _name != "root" ){
foreach(i; 0 .. _level){
start ~= "[";
end ~= "]";
}
content ~= start ~ _name ~ end ~ "\n"; // [section1] ...
[[section2]]
foreach( key, value; _dict )
content ~= "%s=%s\n".format( key, value );
}
foreach(child; _childs){
content ~= child.toString();
}
return content.idup;
}
@property Section dup(){
return new Section( this._name, this.parent, this._level,
this._childs, this._numberOfChild, this._dict );
}
@property string name(){
return _name.idup;
}
@property Section parent(){
return _parent;
}
@property Section parent(Section section){
return _parent = section;
}
@property Section[] childs(){
return _childs.dup;
}
@property size_t level(){
return _level;
}
@property size_t length(){
return _numberOfChild;
}
@property string[] keys(){
return _dict.keys;
}
@property string[] values(){
return _dict.values;
}
@property void rehash(){
_dict.rehash;
foreach(child; _childs)
child.rehash;
}
@property bool empty(){
return _numberOfChild == 0;
}
@property Section front(){
return childs[0];
}
@property Section back(){
return rewind( _parent.level );
}
void popFront(){
_childs =childs[1..$];
}
void popBack(){
Section[] reversed = new Section[]( _level ) ;
while( _level != 0 ){
reversed[ _level - 1 ] = this.back;
}
}
Section save(){
return this;
}
}
/**
* getSection create a Section line with corresponding line
*
* Returns: Section object
*
* Examples:
* --------------------
* string line = "[default]";
* Section section = getSection( line );
* --------------------
*/
Section getSection( string lineSection ){
size_t level = 0;
size_t position = 0;
string name = "";
// get level
while( lineSection[level] == '[' ){
level++;
}
position = level;
// get section name
while( lineSection[position] != ']' ){
name ~= lineSection[position];
position++;
}
return new Section(name, level);
}
More information about the Digitalmars-d
mailing list