cd9b420f090e766111b6ecc43f942efb4e9d9412
[opencv] / apps / vmdemotk / iniparse.tcl
1 # this line is needed for our install script, to keep up with different versions\r
2 # ini_version=1.4\r
3 #\r
4 ##########\r
5 #\r
6 # INIParse v1.4 (C)2000\r
7 #\r
8 #   see AUTHORS\r
9 #\r
10 ##########\r
11 #\r
12 # Usage:\r
13 #   iniparse:openfile <filename> ?RDONLY?\r
14 #   \r
15 # Reads an ini file into memory, for later access (such as read or write),\r
16 # and return an id which can be later used for writing/reading data, and\r
17 # flushing/closing file.\r
18 #\r
19 # Notes:\r
20 # - It doesn't leave the file open, just reads into memory, and returns an id.\r
21 # - If RDONLY is specified (case-sensetive), then calls to writeini will work\r
22 #   only in memory, and changes won't be saved with iniparse:flush, nor\r
23 #   iniparse:closefile.\r
24 #\r
25 ####\r
26 #\r
27 # Usage:\r
28 #   iniparse:flushfile <fileId>\r
29 #   \r
30 # Writes an ini file in memory into its file, without removing data from\r
31 # memory.\r
32 #\r
33 ####\r
34 #\r
35 # Usage:\r
36 #   iniparse:closefile <fileId>\r
37 #   \r
38 # Flushes an ini file in memory into its file, and then removes data from\r
39 # memory.\r
40 #\r
41 ####\r
42 #\r
43 # Usage:\r
44 #   readini <fileId> [ [<keyname>] [<itemname>] ]\r
45 #       Reads <itemname> under <keyname> from <fileId>. If it cannot find\r
46 #       file, <itemname>, or <keyname>, returns an empty string.\r
47 #       If itemname is absent, returns list of all items under keyname.\r
48 #\r
49 # Notes:\r
50 # - This procedure doesn't read directly from the file, but from the\r
51 #   memory-version of the file. If directly the file (not memory version) is\r
52 #   modified after the call to iniparse:openfile, this procedure will not\r
53 #   see the changes in the file, but only changes in memory-version.\r
54 #\r
55 # See: writeini iniparse:openfile\r
56 #\r
57 ####\r
58 #\r
59 # Usage:\r
60 #   writeini <fileId> <keyname> <itemname> <itemvalue>\r
61 #       Writes/modifies <itemname> under <keyname> in <fileId>. If cannot\r
62 #       find <itemname>, or <keyname>, creates a new one.\r
63 #\r
64 # Notes:\r
65 # - This procedure doesn't write directly to the file, but to the\r
66 #   memory-version of the file. If directly the file (not memory version) is\r
67 #   modified after the call to iniparse:openfile, this procedure will not\r
68 #   see the changes in the file, but only changes in memory-version.\r
69 #\r
70 # See: readini iniparse:openfile\r
71 #\r
72 ####\r
73 #\r
74 # Usage:\r
75 #   iniparse:removeitem <fileId> <keyname> <itemname>\r
76 #       Removes <itemname> under <keyname> in <fileId>.\r
77 #\r
78 # Notes:\r
79 # - This procedure doesn't write directly to the file, but to the\r
80 #   memory-version of the file. If directly the file (not memory version) is\r
81 #   modified after the call to iniparse:openfile, this procedure will not\r
82 #   see the changes in the file, but only changes in memory-version.\r
83 #\r
84 # See: readini iniparse:openfile\r
85 #\r
86 ####\r
87 #\r
88 # Usage:\r
89 #   iniparse:removekey <fileId> <keyname>\r
90 #       Removes <keyname> in <fileId>.\r
91 #\r
92 # Notes:\r
93 # - This procedure doesn't write directly to the file, but to the\r
94 #   memory-version of the file. If directly the file (not memory version) is\r
95 #   modified after the call to iniparse:openfile, this procedure will not\r
96 #   see the changes in the file, but only changes in memory-version.\r
97 #\r
98 # See: readini iniparse:openfile\r
99 #\r
100 ####\r
101 #\r
102 # Usage:\r
103 #   iniparse:renameitem <fileId> <keyname> <itemName> <newItemName>\r
104 #       Renames <itemName> under <keyname> in <fileId> to <newItemName>.\r
105 #\r
106 # Notes:\r
107 # - This procedure doesn't write directly to the file, but to the\r
108 #   memory-version of the file. If directly the file (not memory version) is\r
109 #   modified after the call to iniparse:openfile, this procedure will not\r
110 #   see the changes in the file, but only changes in memory-version.\r
111 #\r
112 # See: readini iniparse:openfile\r
113 #\r
114 ####\r
115 #\r
116 # Usage:\r
117 #   iniparse:renamekey <fileId> <keyname> <newKeyName>\r
118 #       Renames <keyname> in <fileId> to <newKeyName>.\r
119 #\r
120 # Notes:\r
121 # - This procedure doesn't write directly to the file, but to the\r
122 #   memory-version of the file. If directly the file (not memory version) is\r
123 #   modified after the call to iniparse:openfile, this procedure will not\r
124 #   see the changes in the file, but only changes in memory-version.\r
125 #\r
126 # See: readini iniparse:openfile\r
127 #\r
128 #############################################################################\r
129 \r
130 package provide iniparse 1.4\r
131 \r
132 set iniparse(freeid) 0\r
133 set iniparse(idlist) {}\r
134 #$iniparse($id,fname)   - filename\r
135 #$iniparse($id,data)    - each line in file are read into an item in this list\r
136 #$iniparse($id,flags)   - this is a list containing these flags:\r
137 #                           RDONLY  : If this flag is set, iniparse:flush will\r
138 #                                     not write anything over file, but still\r
139 #                                     writeini will work (only in memory)\r
140 #\r
141 \r
142 proc rtrimleft {bigstr srcstr} {\r
143   set istring1 [string length $srcstr]\r
144   if {$srcstr == [string range $bigstr 0 [expr $istring1-1]]} {\r
145     return [string range $bigstr $istring1 end]\r
146   }\r
147 }\r
148 \r
149 proc chrchk {arg} {\r
150   if {[string index $arg 0] == "\[" && [string index $arg end] == "\]"} {\r
151     return 1\r
152   } else {return 0}\r
153   return 0\r
154 }\r
155 \r
156 #\r
157 # Usage:\r
158 #   iniparse:openfile <filename> ?RDONLY?\r
159 #   \r
160 # Reads an ini file into memory, for later access (such as read or write),\r
161 # and return an id which can be later used for writing/reading data, and\r
162 # flushing/closing file.\r
163 #\r
164 # Notes:\r
165 # - It doesn't leave the file open, just reads into memory, and returns an id.\r
166 # - If RDONLY is specified (case-sensetive), then calls to writeini will work\r
167 #   only in memory, and changes won't be saved with iniparse:flush, nor\r
168 #   iniparse:closefile.\r
169 #\r
170 proc iniparse:openfile {file args} {\r
171 global iniparse\r
172 \r
173   set fileId [open $file {RDONLY CREAT}]\r
174   set filedata {}\r
175 \r
176   while {![eof $fileId]} {\r
177     set input [gets $fileId]\r
178     if {[string match {\[*\]} $input]} {lappend filedata "" $input} \\r
179     elseif {[string match {*=*} $input] || \\r
180         [string match {#*} $input]} {lappend filedata $input}\r
181   }\r
182 \r
183   close $fileId\r
184 \r
185   set id $iniparse(freeid)\r
186   incr iniparse(freeid)\r
187 \r
188   set iniparse($id,fname) $file\r
189   set iniparse($id,data)  $filedata\r
190   set iniparse($id,flags) $args\r
191   lappend iniparse(idlist) $id\r
192 \r
193   return $id\r
194 }\r
195 \r
196 #\r
197 # Usage:\r
198 #   iniparse:flushfile <fileId>\r
199 #   \r
200 # Writes an ini file in memory into its file, without removing data from\r
201 # memory.\r
202 #\r
203 proc iniparse:flushfile {id} {\r
204 global iniparse\r
205 \r
206   if {[lsearch $iniparse(idlist) $id] == -1} return     ;# No such Id\r
207 \r
208   if {[lsearch $iniparse($id,flags) RDONLY] != -1} return ;# ReadOnly-Flag\r
209 \r
210   set fileId [open $iniparse($id,fname) {WRONLY CREAT TRUNC}]\r
211 \r
212   foreach line $iniparse($id,data) {\r
213     if {[string match {\[*\]} $line]} {puts $fileId "\n$line"} \\r
214     elseif {[string match {*=*} $line] || \\r
215         [string match {#*} $line]} {puts $fileId $line}\r
216   }\r
217   close $fileId\r
218 \r
219   set iniparse($id,flags) [lreplace $iniparse($id,flags) [set idx [lsearch $iniparse($id,flags) CHANGED]] $idx]\r
220 }\r
221 \r
222 #\r
223 # Usage:\r
224 #   iniparse:closefile <fileId>\r
225 #   \r
226 # Flushes an ini file in memory into its file, and then removes data from\r
227 # memory.\r
228 #\r
229 proc iniparse:closefile {id} {\r
230 global iniparse\r
231 \r
232   if {[lsearch $iniparse(idlist) $id] == -1} return     ;# No such Id\r
233 \r
234   iniparse:flushfile $id\r
235   unset iniparse($id,fname)\r
236   unset iniparse($id,data)\r
237   unset iniparse($id,flags)\r
238   set iniparse(idlist) [lreplace $iniparse(idlist) [set idx [lsearch $iniparse(idlist) $id]] $idx]\r
239 }\r
240 \r
241 #\r
242 # Usage:\r
243 #   readini <fileId> [ [<keyname>] [<itemname>] ]\r
244 #       Reads <itemname> under <keyname> from <fileId>. If it cannot find\r
245 #       file, <itemname>, or <keyname>, returns an empty string.\r
246 #       If itemname is absent, returns list of all items under keyname.\r
247 #\r
248 # Notes:\r
249 # - This procedure doesn't read directly from the file, but from the\r
250 #   memory-version of the file. If directly the file (not memory version) is\r
251 #   modified after the call to iniparse:openfile, this procedure will not\r
252 #   see the changes in the file, but only changes in memory-version.\r
253 #\r
254 # See: writeini iniparse:openfile\r
255 #\r
256 proc readini {id args} {\r
257 global iniparse\r
258   set keyfound 0 ; set itemfound 0\r
259   set key [lindex $args 0]\r
260   set item [lindex $args 1]\r
261   set itemlength [string length $item]\r
262   set item "$item="\r
263   set kaccum [list]\r
264   set iaccum [list]\r
265 \r
266   if {[lsearch $iniparse(idlist) $id] == -1} {return ""}   ;# No such Id\r
267 \r
268   set input ""\r
269   set lidx 0                              ;# line index\r
270   set llen [llength $iniparse($id,data)]\r
271   set data $iniparse($id,data)            ;# for fast access\r
272 \r
273   while {$lidx < $llen} {\r
274     set input [lindex $data $lidx]\r
275     if {[chrchk $input]} {\r
276       if {$input == "\[$key\]"} {\r
277         # looks like we found our key..\r
278         set keyfound 1 ; break\r
279       } else {\r
280         set keyfound 0\r
281         regsub -all {\[|\]} $input {} baccum\r
282         lappend kaccum $baccum\r
283       }\r
284     }\r
285     incr lidx\r
286   }\r
287   incr lidx\r
288 \r
289   if {$keyfound == 1} {\r
290     while {$lidx < $llen} {\r
291       set input [lindex $data $lidx]\r
292       if {![chrchk $input]} {\r
293         if {[string range $input 0 $itemlength]==$item} {\r
294           set fValue [rtrimleft $input $item]\r
295           set itemfound 1\r
296           break\r
297         } else {\r
298           set itemNdx [string first "=" $input]\r
299           if {$itemNdx != -1} {\r
300             lappend iaccum [string range $input 0 [expr $itemNdx - 1]]\r
301           }\r
302         }\r
303       } elseif {[chrchk $input]} {\r
304         # oops, we hit the next key.. looks like that item isnt here.\r
305         break\r
306       }\r
307       incr lidx\r
308     }\r
309   } elseif {$keyfound == 0} {\r
310     if {[llength $args] == 0} {\r
311        return $kaccum\r
312     } else {\r
313        return ""       ;# no key exists called $key\r
314     }\r
315   }\r
316   if {$itemfound == 1} {\r
317     return $fValue\r
318   } elseif {[llength $args] != 2} {\r
319     return $iaccum\r
320   } else {\r
321     return ""       ;# no item exists called "[string range $item 0 [expr [string length $item] - 2]]"\r
322   }\r
323 }\r
324 \r
325 #\r
326 # Usage:\r
327 #   writeini <fileId> <keyname> <itemname> <itemvalue>\r
328 #       Writes/modifies <itemname> under <keyname> in <fileId>. If cannot\r
329 #       find <itemname>, or <keyname>, creates a new one.\r
330 #\r
331 # Notes:\r
332 # - This procedure doesn't write directly to the file, but to the\r
333 #   memory-version of the file. If directly the file (not memory version) is\r
334 #   modified after the call to iniparse:openfile, this procedure will not\r
335 #   see the changes in the file, but only changes in memory-version.\r
336 #\r
337 # See: readini iniparse:openfile\r
338 #\r
339 proc writeini {id key item value} {\r
340 global iniparse\r
341   set fileline ""\r
342   set keyfound 0\r
343   set itemfound 0\r
344   set itemlength [string length $item]\r
345   set item "$item="\r
346 \r
347   if {[lsearch $iniparse(idlist) $id] == -1} return   ;# No such Id\r
348 \r
349   set input ""\r
350   set lidx 0                              ;# line index\r
351   set llen [llength $iniparse($id,data)]\r
352   set fileline $iniparse($id,data)\r
353   set data ""\r
354 \r
355   foreach line $fileline {\r
356     if {(!$keyfound)} {          ;# We will search for the key.\r
357         if {$line=="\[$key\]"} {\r
358                 lappend data "" $line\r
359                 set keyfound 1\r
360                 continue\r
361         }\r
362     }\r
363     if {($keyfound) && (!$itemfound) && [chrchk $line]} {  ;# We hit the next key!\r
364         lappend data "$item$value"\r
365         lappend data "" $line\r
366         set itemfound 1\r
367         continue\r
368     }\r
369     if {($keyfound) && (!$itemfound)} {  ;# We will search for the item\r
370         if {[string range $line 0 $itemlength]==$item} {\r
371                 lappend data "$item$value"\r
372                 set itemfound 1\r
373                 continue\r
374         }\r
375     }\r
376     # Because it doesn't match anything above, we print the line to file\r
377     if {[chrchk $line]} {lappend data "" $line} \\r
378         else {lappend data $line}\r
379   }\r
380 \r
381   if {(!$keyfound) && (!$itemfound)} {\r
382         lappend data "" "\[$key\]"\r
383         lappend data "$item$value"\r
384   } elseif {$keyfound && (!$itemfound)} {\r
385         lappend data "$item$value"\r
386   }\r
387 \r
388   set iniparse($id,data) $data\r
389 }\r
390 \r
391 #\r
392 # Usage:\r
393 #   iniparse:removeitem <fileId> <keyname> <itemname>\r
394 #       Removes <itemname> under <keyname> in <fileId>.\r
395 #\r
396 # Notes:\r
397 # - This procedure doesn't write directly to the file, but to the\r
398 #   memory-version of the file. If directly the file (not memory version) is\r
399 #   modified after the call to iniparse:openfile, this procedure will not\r
400 #   see the changes in the file, but only changes in memory-version.\r
401 #\r
402 # See: readini iniparse:openfile\r
403 #\r
404 proc iniparse:removeitem {id key item} {\r
405 global iniparse\r
406   set fileline ""\r
407   set keyfound 0\r
408   set itemfound 0\r
409   set itemlength [string length $item]\r
410   set item "$item="\r
411 \r
412   if {[lsearch $iniparse(idlist) $id] == -1} return   ;# No such Id\r
413 \r
414   set fileline $iniparse($id,data)\r
415   set data {}\r
416 \r
417   foreach line $fileline {\r
418     if {(!$keyfound)} {          ;# We will search for the key.\r
419         if {$line=="\[$key\]"} {\r
420                 lappend data "" $line\r
421                 set keyfound 1\r
422                 continue\r
423         } else {lappend data $line; continue}\r
424     }\r
425     if {($keyfound) && (!$itemfound) && [chrchk $line]} {  ;# We hit the next key!\r
426         lappend data "" $line\r
427         set itemfound 1\r
428         continue\r
429     }\r
430     if {($keyfound) && (!$itemfound)} {  ;# We will search for the item\r
431         if {[string range $line 0 $itemlength]==$item} {\r
432                 set itemfound 1\r
433                 continue        ;# We don't print the line to file\r
434         } else {lappend data $line; continue}\r
435     }\r
436     # Because it doesn't match anything above, we print the line to file\r
437     if {[chrchk $line]} {lappend data "" $line} \\r
438         else {lappend data $line}\r
439   }\r
440 \r
441   set iniparse($id,data) $data\r
442 }\r
443 \r
444 #\r
445 # Usage:\r
446 #   iniparse:removekey <fileId> <keyname>\r
447 #       Removes <keyname> in <fileId>.\r
448 #\r
449 # Notes:\r
450 # - This procedure doesn't write directly to the file, but to the\r
451 #   memory-version of the file. If directly the file (not memory version) is\r
452 #   modified after the call to iniparse:openfile, this procedure will not\r
453 #   see the changes in the file, but only changes in memory-version.\r
454 #\r
455 # See: readini iniparse:openfile\r
456 #\r
457 proc iniparse:removekey {id key} {\r
458 global iniparse\r
459   set fileline ""\r
460   set keyfound 0\r
461   set keyfinished 0\r
462 \r
463   if {[lsearch $iniparse(idlist) $id] == -1} return   ;# No such Id\r
464 \r
465   set fileline $iniparse($id,data)\r
466   set data {}\r
467 \r
468   foreach line $fileline {\r
469     if {(!$keyfound)} {          ;# We will search for the key.\r
470         if {$line=="\[$key\]"} {\r
471                 set keyfound 1\r
472                 continue\r
473         }\r
474     }\r
475     if {($keyfound) && (!$keyfinished) && (![chrchk $line])} {  ;# We are waiting for the next key\r
476         continue\r
477     }\r
478     if {($keyfound) && (!$keyfinished) && ([chrchk $line])} {  ;# We are hit the next key!\r
479         lappend data "" $line\r
480         set keyfinished 1\r
481         continue\r
482     }\r
483     # Because it doesn't match anything above, we print the line to file\r
484     if {[chrchk $line]} {lappend data "" $line} \\r
485         else {lappend data $line}\r
486   }\r
487 \r
488   set iniparse($id,data) $data\r
489 }\r
490 \r
491 #\r
492 # Usage:\r
493 #   iniparse:renameitem <fileId> <keyname> <itemName> <newItemName>\r
494 #       Renames <itemName> under <keyname> in <fileId> to <newItemName>.\r
495 #\r
496 # Notes:\r
497 # - This procedure doesn't write directly to the file, but to the\r
498 #   memory-version of the file. If directly the file (not memory version) is\r
499 #   modified after the call to iniparse:openfile, this procedure will not\r
500 #   see the changes in the file, but only changes in memory-version.\r
501 #\r
502 # See: readini iniparse:openfile\r
503 #\r
504 proc iniparse:renameitem {id key olditem newitem} {\r
505   writeini $id $key $newitem [readini $id $key $olditem]\r
506   iniparse:removeitem $id $key $olditem\r
507 }\r
508 \r
509 #\r
510 # Usage:\r
511 #   iniparse:renamekey <fileId> <keyname> <newKeyName>\r
512 #       Renames <keyname> in <fileId> to <newKeyName>.\r
513 #\r
514 # Notes:\r
515 # - This procedure doesn't write directly to the file, but to the\r
516 #   memory-version of the file. If directly the file (not memory version) is\r
517 #   modified after the call to iniparse:openfile, this procedure will not\r
518 #   see the changes in the file, but only changes in memory-version.\r
519 #\r
520 # See: readini iniparse:openfile\r
521 #\r
522 proc iniparse:renamekey {id oldkey newkey} {\r
523 global iniparse\r
524 \r
525   if {[lsearch $iniparse(idlist) $id] == -1} return   ;# No such Id\r
526 \r
527   set fileline $iniparse($id,data)\r
528   set data {}\r
529 \r
530   foreach line $fileline {\r
531         if {$line=="\[$oldkey\]"} {\r
532                 lappend data "" "\[$newkey\]"\r
533                 continue\r
534         } else {\r
535                 if {[chrchk $line]} {lappend data "" $line} \\r
536                 else {lappend data $line}\r
537         }\r
538   }\r
539 \r
540   set iniparse($id,data) $data\r
541 }\r
542 \r