1 module econf;
2 
3 import std.stdio;
4 import std.conv : to;
5 import std.string;
6 import std.array;
7 import std.file : readText;
8 import std.uni : isNumber;
9 import std.conv : parse;
10 public import econf.tokens;
11 public import econf.extra;
12 
13 enum EType {
14 	Str,
15 	Int,
16 	Float,
17 	Hex,
18 
19 	StrArr,
20 	IntArr,
21 	FloatArr,
22 	HexArr,
23 
24     Obj
25 }
26 
27 class EConf {
28 	private string f;
29 	EToken[int] toks_asnum;
30 	private string[string] toks;
31 	private EToken[string] toks_at_string;
32 	private int currtok=0;
33 
34 	private void addTok(string str) {
35 		this.toks_asnum[currtok]=new EToken(str);
36 		this.currtok+=1;
37 	}
38 
39 	private void toksToObject() {
40 		int j=0;
41 		while(j<toks_asnum.length) {
42 			this.toks[this.toks_asnum[j].getString()]=
43 				this.toks_asnum[j+1].getString();
44 			this.toks_at_string[this.toks_asnum[j].getString()]=
45 				this.toks_asnum[j+1];
46 			j+=2;
47 		}
48 	}
49 
50 	this(string f) {
51 		int i=0;
52 		while(i<this.f.length) {
53 			if(this.f[i]==' '||this.f[i]=='\t'||this.f[i]=='\n') {i+=1; continue;}
54 			else if(this.f[i]=='#') {
55 				if(this.f.indexOf("\n")==-1) {
56 					break;
57 				}
58 				else {
59 					i=to!int(this.f.indexOf("\n")+1);
60 					continue;
61 				}
62 			}
63 			else {
64 				if(this.f[i]=='\"') {
65 					// STRING
66 					string temp_str="\"";
67 					for(int j=i+1; j<this.f.length; j++) {
68 						if(this.f[j]=='\"') {
69 							temp_str~="\"";
70 							i=j+1;
71 							j=to!int(this.f.length+1);
72 						}
73 						else {
74 							temp_str~=this.f[j];
75 						}
76 					}
77 					addTok(temp_str.strip());
78 					temp_str="";
79 				}
80 				else {
81 					// FLOAT, INTEGER OR IDENTIFIER
82 					if(isNumber(this.f[i])) {
83 						// FLOAT OR INTEGER
84 						string temp_num=""~this.f[i];
85 						for(int j=i+1; j<this.f.length; j++) {
86 							if(this.f[j]==' '
87 							 ||this.f[j]=='\"'
88 							 ||this.f[j]=='['
89 							 ||this.f[j]==']'
90                              ||this.f[j]=='{'
91                              ||this.f[j]=='}'
92 							 ||this.f[j]=='\t'
93 							 ||this.f[j]=='\n') {
94 								i=j;
95 								j=to!int(this.f.length+1);
96 							}
97 							else {
98 								temp_num~=this.f[j];
99 								if(j+1==this.f.length) {
100 									i=j+1;
101 								}
102 							}
103 						}
104 						addTok(temp_num.strip());
105 						temp_num="";
106 					}
107 					else if(this.f[i]!='['&&this.f[i]!=']'
108                          &&this.f[i]!='{'&&this.f[i]!='}'){
109 						// IDENTIFIER
110 						string temp_i="";
111 						for(int j=i; j<this.f.length; j++) {
112 							if(this.f[j]==' '
113 							 ||this.f[j]=='\"'
114 							 ||this.f[j]=='['
115 							 ||this.f[j]==']'
116                              ||this.f[j]=='{'
117                              ||this.f[j]=='}'
118 							 ||isNumber(this.f[j])
119 							 ||this.f[j]=='\t'
120 							 ||this.f[j]=='\n') {
121 								i=j;
122 								j=to!int(this.f.length+1);
123 							}
124 							else {
125 								temp_i~=this.f[j];
126 								if(j+1==this.f.length) {
127 									i=j+1;
128 								}
129 							}
130 						}
131 						if(temp_i.strip()!="") addTok(temp_i.strip());
132 						temp_i="";
133 					}
134 					else {
135 						// START_ARRAY or END_ARRAY or START_OBJECT or END_OBJECT
136 						addTok(""~this.f[i]);
137 						i+=1;
138 					}
139 				}
140 			}
141 		}
142 		this.toks_asnum=EConfInitArrays(this.toks_asnum);
143         this.toks_asnum=EConfInitObjects(this.toks_asnum);
144 		toksToObject();
145 	}
146 
147 	template get(string name) {
148 		string Str() {
149 			if(name in this.toks) {
150 				return this.toks[name][1..$-1];
151 			}
152 			else {
153 				throw new StringException("Error: undefined token \""~
154 				    name~"\"!");
155 			}
156 		}
157 		string[int] StrArr() {
158 			if(name in this.toks) {
159 				EToken[int] chs=this.toks_at_string[name].childs;
160 				string[int] arr;
161 				for(int i=0; i<chs.length; i++) {
162 					arr[i]=chs[i].getString()[1..$-1];
163 				}
164 				return arr;
165 			}
166 			else {
167 				throw new StringException("Error: undefined token \""~
168 				    name~"\"!");
169 			}
170 		}
171 		int Int() {
172 			if(name in this.toks) {
173 				return to!int(this.toks[name]);
174 			}
175 			else {
176 				throw new StringException("Error: undefined token \""~
177 				    name~"\"!");
178 			}
179 		}
180 		float Float() {
181 			if(name in this.toks) {
182 				return to!float(this.toks[name]);
183 			}
184 			else {
185 				throw new StringException("Error: undefined token \""~
186 				    name~"\"!");
187 			}
188 		}
189         int[int] IntArr() {
190             if(name in this.toks) {
191 				EToken[int] chs=this.toks_at_string[name].childs;
192 				int[int] arr;
193 				for(int i=0; i<chs.length; i++) {
194 					arr[i]=to!int(chs[i].getString());
195 				}
196 				return arr;
197 			}
198 			else {
199 				throw new StringException("Error: undefined token \""~
200 				    name~"\"!");
201 			}
202         }
203         float[int] FloatArr() {
204             if(name in this.toks) {
205 				EToken[int] chs=this.toks_at_string[name].childs;
206 				float[int] arr;
207 				for(int i=0; i<chs.length; i++) {
208 					arr[i]=to!float(chs[i].getString());
209 				}
210 				return arr;
211 			}
212 			else {
213 				throw new StringException("Error: undefined token \""~
214 				    name~"\"!");
215 			}
216         }
217         int Hex() {
218             if(name in this.toks) {
219 				return to!int(this.toks[name][2..$],16);
220 			}
221 			else {
222 				throw new StringException("Error: undefined token \""~
223 				    name~"\"!");
224 			}
225         }
226         int[int] HexArr() {
227             if(name in this.toks) {
228 				EToken[int] chs=this.toks_at_string[name].childs;
229 				int[int] arr;
230 				for(int i=0; i<chs.length; i++) {
231 					arr[i]=to!int(chs[i].getString(),16);
232 				}
233 				return arr;
234 			}
235 			else {
236 				throw new StringException("Error: undefined token \""~
237 				    name~"\"!");
238 			}
239         }
240         EToken[string] Obj() {
241             if(name in this.toks) {
242 				EToken[int] chs=this.toks_at_string[name].childs;
243 				EToken[string] arr;
244 				int i=0;
245                 while(i<chs.length) {
246                     arr[chs[i].getString()]=chs[i+1];
247                     i+=2;
248                 }
249 				return arr;
250 			}
251 			else {
252 				throw new StringException("Error: undefined token \""~
253 				    name~"\"!");
254 			}
255         }
256 	}
257 	template put(T) {
258 		T put(string name, T value) {
259 			T a;
260 			string b;
261 			if(typeid(a)==typeid(b)) {
262 				this.toks[name]="\""~value~"\"";
263 			}
264 			else {
265 				this.toks[name]=to!string(value);
266 			}
267 		}
268 	}
269 	string toksToString() {
270 		string all_toks="";
271 		int j=0;
272 		while(j<this.toks_asnum.length) {
273 			all_toks~=this.toks_asnum[j].getString()
274 			~" "~this.toks_asnum[j+1].getString()~"\n";
275 			j+=2;
276 		}
277 		return all_toks.strip();
278 	}
279 }