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








bioinfornatics <bioinfornatics fedoraproject.org>