digitalmars.D - [RFC] ini parser
- bioinfornatics (373/373) Feb 22 2012 I have wrote a ini parser it can use bidirectional range
- bioinfornatics (3/3) Feb 22 2012 update (minor)
I have wrote a ini parser it can use bidirectional range example of ini file able to parse: _______________________________________ [sectionA] param1=3Dvalue1 param2=3Dvalue2 [[subSectionA]] param1sub=3Dvalue1sub [sectionB] param3=3Dvalue3 ; I am a comment param4=3Dvalue4 [sectionC] param5=3Dvalue5 param6=3Dvalue6 _______________________________________ Example to code who use ini parser _______________________________________ import std.string; import std.stdio; import std.ini; void main( ){ writeln( "0 - Starting test" ); IniFile tester =3D 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=3Dvalue1 param2=3Dvalue2 [[subSectionA]] param1sub=3Dvalue1sub , [sectionB] param3=3Dvalue3 param4=3Dvalue4 , [sectionC] param5=3Dvalue5 param6=3Dvalue6 ], 3 - object is null: false 4 - number of section: 3 5 - sectionA: [sectionA] param1=3Dvalue1 param2=3Dvalue2 [[subSectionA]] param1sub=3Dvalue1sub 6 - sectionA.param1: value1 7 - first section: [sectionA] param1=3Dvalue1 param2=3Dvalue2 [[subSectionA]] param1sub=3Dvalue1sub 8 - popfront 9 - first section: [sectionB] param3=3Dvalue3 param4=3Dvalue4 _______________________________________ 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 =3D "~/myGreatSetup.conf"; * Section sections =3D configFile.open( filePath ); * -------------------- */ IniFile open( string filePath ){ Section root =3D new Section("root", 0); // root section Section currentSection =3D root; // reference to current section Section nextSection =3D null; File iniFile =3D File( filePath, "r" ); foreach( line; iniFile.byLine() ){ // read line by line try{ line =3D line.stripLeft().stripRight(); if( line =3D=3D "" || line[0] =3D=3D ';' ){ // empty line line or comment line continue; } else if( line[0] =3D=3D '[' ){ // section start nextSection =3D 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 =3D nextSection; // now current section go to next one } else if( currentSection.level =3D=3D nextSection.level ){ // currentSection.level =3D nextSection.level currentSection =3D currentSection.rewind( currentSection.parent.level ); currentSection.addChild( nextSection ); currentSection =3D nextSection; } else{ // currentSection.level > nextSection.level currentSection =3D currentSection.rewind( nextSection.level - 1); currentSection.addChild( nextSection ); currentSection =3D nextSection; } } else{ // read information corresponding to a section string[] words =3D split(cast(string)line, "=3D"); // get key / value peer foreach( ref string word; words ) word.stripRight().stripLeft(); // remove space, before and after word currentSection[ words[0] ] =3D 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 =3D name; this._level =3D level; this._childs =3D []; this._numberOfChild =3D 0; this._dict =3D 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 =3D name; this._level =3D level; this._childs.length =3D childs.length; foreach(size_t index, child; childs) this._childs[index] =3D child.dup; this._numberOfChild =3D numberOfChild; this._dict =3D dict; } /** * addChild is used for add a subsection to current section * * Params: Section */ void addChild( ref Section section ){ if( _numberOfChild >=3D _childs.length ) _childs.length =3D _childs.length + 5; // resize +5 for not resize 1 by 1 section.parent =3D this; _childs[_numberOfChild] =3D section; _numberOfChild++; } /** * Resize object to same size as data contained by the object */ property void shrink(){ _childs.length =3D _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 =3D null; bool isSearching =3D true; size_t index =3D 0; while( isSearching ){ if( index >=3D _numberOfChild ) isSearching =3D false; else if( _childs[index].name =3D=3D name ){ isSearching =3D false; section =3D _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] =3D 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 =3D null; if( _level =3D=3D levelToGo) section =3D this; else if( _level >=3D levelToGo) section =3D _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 =3D ""; string start =3D ""; string end =3D ""; if( _name !=3D "root" ){ foreach(i; 0 .. _level){ start ~=3D "["; end ~=3D "]"; } content ~=3D start ~ _name ~ end ~ "\n"; // [section1] ... [[section2]] foreach( key, value; _dict ) content ~=3D "%s=3D%s\n".format( key, value ); } foreach(child; _childs){ content ~=3D 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 =3D 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 =3D=3D 0; } property Section front(){ return childs[0]; } property Section back(){ return rewind( _parent.level ); } void popFront(){ _childs =3Dchilds[1..$]; } void popBack(){ Section[] reversed =3D new Section[]( _level ) ; while( _level !=3D 0 ){ reversed[ _level - 1 ] =3D this.back; } } Section save(){ return this; } } /** * getSection create a Section line with corresponding line * * Returns: Section object * * Examples: * -------------------- * string line =3D "[default]"; * Section section =3D getSection( line ); * -------------------- */ Section getSection( string lineSection ){ size_t level =3D 0; size_t position =3D 0; string name =3D ""; // get level while( lineSection[level] =3D=3D '[' ){ level++; } position =3D level; // get section name while( lineSection[position] !=3D ']' ){ name ~=3D lineSection[position]; position++; } return new Section(name, level); }
Feb 22 2012
update (minor) I have do a pull request here: https://github.com/D-Programming-Language/phobos/pull/449
Feb 22 2012