1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2008, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * Author: Alexey Krivonogov ( gentee )
11 *
12 ******************************************************************************/
13
14 /*-----------------------------------------------------------------------------
15 * Id: ini L "INI File"
16 *
17 * Summary: INI files. This library allows you to work with ini files.
18 Variables of the ini type allow you to work with them. For using
19 this library, it is required to specify the file ini.g (from
20 lib\ini subfolder) with include command. #srcg[
21 |include : $"...\gentee\lib\ini\ini.g"]
22 *
23 * List: *#lng/methods#,ini_delkey,ini_delsection,ini_getnum,ini_getvalue,
24 ini_keys,ini_read,ini_sections,ini_setnum,ini_setvalue,ini_write,
25 *#lng/funcs#,inigetval,inisetval
26 *
27 -----------------------------------------------------------------------------*/
28
29 type ini {
30 str data
31 arrstr lines
32 arr offset of uint
33 }
34
35 /*-----------------------------------------------------------------------------
36 * Id: ini_read F2
37 *
38 * Summary: Read data from a file.
39 *
40 * Params: filename - The name of the ini file.
41 *
42 -----------------------------------------------------------------------------*/
43
44 method ini.read( str filename )
45 {
46 this.data.read( filename )
47 this.data.lines( this.lines, 1, this.offset )
48 }
49
50 /*-----------------------------------------------------------------------------
51 * Id: ini_write F2
52 *
53 * Summary: Save data into an ini file.
54 *
55 * Params: filename - The name of the ini file.
56 *
57 * Return: Returns the size of the written data.
58 *
59 -----------------------------------------------------------------------------*/
60
61 method uint ini.write( str filename )
62 {
63 return this.data.write( filename )
64 }
65
66 /*-----------------------------------------------------------------------------
67 * Id: ini_sections F2
68 *
69 * Summary: Getting the list of sections. All sections will be written into
70 an array of strings.
71 *
72 * Params: ret - The array of strings the names of sections will be written to.
73 *
74 * Return: #lng/retpar(ret)
75 *
76 -----------------------------------------------------------------------------*/
77
78 method arrstr ini.sections( arrstr ret )
79 {
80 uint end
81
82 ret.clear()
83 foreach cur, this.lines
84 {
85 if cur[ 0 ] == '['
86 {
87 end = 1
88 while cur[ end ] && cur[ end ] != ']' : end++
89 if cur[ end ] == ']'
90 {
91 uint ptr = cur.ptr() + 1
92 uint len = end - 1
93 ptr = trimsys( ptr, &len )
94 ret[ ret.expand( 1 ) ].substr( cur, ptr - cur.ptr(), len )
95 }
96 }
97 }
98 return ret
99 }
100
101 method uint ini.range( str section, uint last )
102 {
103 uint from to i
104
105 fornum i, *this.lines
106 {
107 if (this.lines[ i ])[0] == '['
108 {
109 if from : break
110
111 str name = this.lines[ i ]
112 uint right = name.findch( ']' )
113 if right < *name : name.setlen( right + 1 )
114 name.trim( '[', $TRIM_LEFT | $TRIM_RIGHT | $TRIM_PAIR )
115 name.trimsys()
116 if name %== section : from = i + 1
117 }
118 }
119 last->uint = i - 1
120 return from
121 }
122
123
124 /*-----------------------------------------------------------------------------
125 * Id: ini_getvalue F2
126 *
127 * Summary: Get the value of an entry.
128 *
129 * Params: section - Section name.
130 key - Key name.
131 value - The string for getting the value.
132 defval - The value to be assigned if the entry is not found.
133 *
134 * Return: Returns 1 if the entry is found and 0 otherwise.
135 *
136 -----------------------------------------------------------------------------*/
137
138 method uint ini.getvalue( str section, str key, str value, str defvalue )
139 {
140 uint from to ret i
141 arrstr temp
142
143 from = this.range( section, &to )
144 if from
145 {
146 for i = from, i <= to, i++
147 {
148 this.lines[i].split( temp, '=', $SPLIT_NOSYS | $SPLIT_FIRST |
149 $SPLIT_EMPTY )
150 if *temp == 2 && key %== temp[0]
151 {
152 value = temp[1]
153 ret = i
154 break
155 }
156 }
157 }
158 if !from || i > to : value = defvalue
159
160 return ret
161 }
162
163 /*-----------------------------------------------------------------------------
164 * Id: ini_getnum F2
165 *
166 * Summary: Get the numerical value of an entry.
167 *
168 * Params: section - Section name.
169 key - Key name.
170 defval - The value to be assigned if the entry is not found.
171 *
172 * Return: The numerical value of the key.
173 *
174 -----------------------------------------------------------------------------*/
175
176 method uint ini.getnum( str section, str key, uint defvalue )
177 {
178 str value
179
180 if !this.getvalue( section, key, value, "" ) : return defvalue
181
182 return uint( value )
183 }
184
185 /*-----------------------------------------------------------------------------
186 * Id: ini_keys F2
187 *
188 * Summary: Get the list of entries in this section. All entries will be
189 written into an array of strings.
190 *
191 * Params: section - Section name.
192 ret - The array of strings the names of entries will be written to.
193 *
194 * Return: #lng/retpar( ret )
195 *
196 -----------------------------------------------------------------------------*/
197
198 method arrstr ini.keys( str section, arrstr ret )
199 {
200 uint from to i
201 arrstr temp
202
203 ret.clear()
204 from = this.range( section, &to )
205
206 if from
207 {
208 for i = from, i <= to, i++
209 {
210 this.lines[i].split( temp, '=', $SPLIT_NOSYS | $SPLIT_FIRST |
211 $SPLIT_EMPTY )
212 if *temp == 2 && (temp[0])[0] != ';'
213 {
214 ret[ ret.expand( 1 )] = temp[0]
215 }
216 }
217 }
218 return ret
219 }
220
221 /*-----------------------------------------------------------------------------
222 * Id: ini_setvalue F2
223 *
224 * Summary: Write the value of an entry.
225 *
226 * Params: section - Section name.
227 key - Key name.
228 value - The value of the entry being written.
229 *
230 -----------------------------------------------------------------------------*/
231
232 method ini.setvalue( str section, str key, str value )
233 {
234 uint line from to i
235 str stemp
236 str result = "\(key)=\(value)\l"
237
238 line = this.getvalue( section, key, stemp, "" )
239 if line
240 {
241 this.data.replace( this.offset[ line ], ?( line == *this.lines - 1,
242 *this.lines[ line ],
243 this.offset[ line + 1 ] - this.offset[ line ] ), result )
244 }
245 else
246 {
247 from = this.range( section, &to )
248 if !from
249 {
250 this.data += "\l[\(section)]\l\(result)"
251 }
252 else
253 { // Ищем последнюю непустую после которой надо вставлять
254 while to > from && !*this.lines[ to ] : to--
255 if to == *this.lines - 1 // последняя строка
256 {
257 this.data += "\l\(result)"
258 }
259 else
260 {
261 this.data.insert( this.offset[ to + 1 ], result )
262 }
263 }
264 }
265 this.data.lines( this.lines, 1, this.offset )
266 }
267
268 /*-----------------------------------------------------------------------------
269 * Id: ini_setnum F2
270 *
271 * Summary: Write the numerical value of an entry.
272 *
273 * Params: section - Section name.
274 key - Key name.
275 value - The value of the entry being written.
276 *
277 -----------------------------------------------------------------------------*/
278
279 method ini.setnum( str section, str key, uint value )
280 {
281 this.setvalue( section, key, str( value ))
282 }
283
284 /*-----------------------------------------------------------------------------
285 * Id: ini_delsection F2
286 *
287 * Summary: Deleting a section.
288 *
289 * Params: section - The name of the section being deleted.
290 *
291 -----------------------------------------------------------------------------*/
292
293 method ini.delsection( str section )
294 {
295 uint from to start
296 from = this.range( section, &to )
297 if from
298 {
299 start = this.offset[ from - 1 ]
300 this.data.del( start, ?( to == *this.lines - 1,
301 *this.data - start, this.offset[ to + 1 ] - start ))
302 this.data.lines( this.lines, 1, this.offset )
303 }
304 }
305
306 /*-----------------------------------------------------------------------------
307 * Id: ini_delkey F2
308 *
309 * Summary: Deleting a key.
310 *
311 * Params: section - Section name.
312 key - The name of the entry being deleted.
313 *
314 -----------------------------------------------------------------------------*/
315
316 method ini.delkey( str section, str key )
317 {
318 uint line start
319
320 line = this.getvalue( section, key, "", "" )
321 if line
322 {
323 start = this.offset[ line ]
324 this.data.del( start, ?( line == *this.lines - 1,
325 *this.data - start, this.offset[ line + 1 ] - start ))
326 this.data.lines( this.lines, 1, this.offset )
327 }
328 }
329
330 /*-----------------------------------------------------------------------------
331 * Id: inigetval F
332 *
333 * Summary: Get the value of an entry from an ini file.
334 *
335 * Params: ininame - The name of the ini file.
336 section - Section name.
337 key - Key name.
338 value - The string for writing the value.
339 defval - The value that will be inserted in case of an error or /
340 if there is not such an entry.
341 *
342 * Return: #lng/retpar( value )
343 *
344 -----------------------------------------------------------------------------*/
345
346 func str inigetval( str ininame, str section, str key, str value, str defval )
347 {
348 ini tini
349
350 tini.read( ininame )
351 tini.getvalue( section, key, value, defval )
352 return value
353 }
354
355 /*-----------------------------------------------------------------------------
356 ** Id: inisetval F
357 *
358 * Summary: Write the value of an entry into an ini file.
359 *
360 * Params: ininame - The name of the ini file.
361 section - Section name.
362 key - Key name.
363 value - The value of the entry being written.
364 *
365 * Return: #lng\retf#
366 *
367 -----------------------------------------------------------------------------*/
368
369 func uint inisetval( str ininame, str section, str key, str value )
370 {
371 ini tini
372
373 tini.read( ininame )
374 tini.setvalue( section, key, value )
375 return tini.write( ininame )
376 }
377
378