1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
|
#!/usr/bin/tclsh
# Part of MCU 8051 IDE ( http://https://sourceforge.net/projects/mcu8051ide/ )
############################################################################
# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 by Martin Ošmera #
# martin.osmera@gmail.com #
# #
# Copyright (C) 2014 by Moravia Microsystems, s.r.o. #
# martin.osmera@gmail.com #
# #
# This program is free software; you can redistribute it and#or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the #
# Free Software Foundation, Inc., #
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
############################################################################
# >>> File inclusion guard
if { ! [ info exists _SETTINGS_TCL ] } {
set _SETTINGS_TCL _
# <<< File inclusion guard
# --------------------------------------------------------------------------
# DESCRIPTION
# Implements interface to program settings (which are stored in a file)
# --------------------------------------------------------------------------
class Settings {
public common dir_sep [file separator] ;# Directory separator (eg. '/')
public common settings_count 0 ;# Counter of instances
private variable isEmpty 1 ;# Is settings array empty
private variable isReady 0 ;# Is interface ready
private variable directory ;# Path to directory with settings file
private variable filename ;# Name of file with settings related to this instance
private variable fileFullPath ;# Full name of settings file (including directory)
private variable configArray {} ;# Content of settings maneged by this interface
## Object contructor
# @parm String configDir - Path to directory with settings file
# @parm String configFileName - Name of file with settings
constructor {configDir configFileName} {
incr settings_count ;# increment instance conter
# Incalize object variables
set configArray "::Settings::S${settings_count}" ;# Array of settings
set directory [string trimright $configDir "/\/"] ;# Path to directory with settings file
set filename [string trimleft $configFileName "/\/"] ;# Name of file with settings
set fileFullPath "${directory}${dir_sep}${filename}" ;# Full name of settings file
# If specified file does not exist -> create it
if {![file exists $fileFullPath]} {
if {[catch {
file mkdir $directory
close [open $fileFullPath w 0640]
}]} then {
return
} else {
set isReady 1
}
# Else check if the file is readable and writable
} else {
if {$::MICROSOFT_WINDOWS || ([file readable $fileFullPath] && [file writable $fileFullPath])} {
set isReady 1
} else {
return
}
}
# Load settings from the file
reLoadConfig
}
## Object destructor
destructor {
}
## (Re)load settings from config file
# @return result
public method reLoadConfig {} {
# Check if file is readable
if {!$::MICROSOFT_WINDOWS && ![file readable $fileFullPath]} {
return 0
}
# Read content of config file and store it as list of lines into fileData
set configFile [open $fileFullPath r]
set fileData [read $configFile]
set fileData [regsub -all {\r\n} $fileData "\n"]
set fileData [regsub -all {\r} $fileData "\n"]
set fileData [split $fileData "\n"]
close $configFile
# Parse content of the file
set category {general}
foreach line $fileData {
# Local variables
set line [string trim $line] ;# Line of config file
set key {} ;# Key
set value {} ;# Value for the key
# Skip empty lines
if {$line == {}} {continue}
# Handle category declaration
if {[regexp {^\[\s*[\w \t]+\s*\]$} $line]} {
set category [string trim $line "\[\] \t"]
# Handle key and its value
} elseif {[regexp {^\s*[\w \t:]+\s*\=\s*\".*\"\s*$} $line]} {
# Determinate key
regexp {^\s*[\w \t:]+\s*\=} $line key
set key [string trim $key "=\t "]
# Determinate value
regexp {\s*\".*\"\s*$} $line value
set value [string trim $value]
regsub {^\"} $value {} value
regsub {\"$} $value {} value
regsub -all "\a" $value "\n" value
# Set key and value to array
set "$configArray\($category/$key\)" $value
}
}
# Set variable isEmpty
if {[array size $configArray] != 0} {
set isEmpty 0
} else {
set isEmpty 1
}
# return result
return 1
}
## Save current content of $configArray to config file
# @return result
public method saveConfig {} {
# Check if file is writable
if {![file writable $fileFullPath]} {
return 0
}
# Local variables
set configFile [open $fileFullPath w 0640] ;# ID of config file chanel
set categories {general} ;# Name of current category
# Determinate list of categories
foreach key [array names $configArray] {
# Determinate category
regexp {^.+/} $key category
set category [string trimright $category {/}]
# Append category to the list
if {[lsearch $categories $category] == -1} {
lappend categories $category
}
}
# Iterate over categories and save them to the file
foreach category $categories {
# Get names of keys in current category
set keys [array names $configArray -regexp "$category/"]
# Save category declaration
puts $configFile "\n\[$category\]"
# Iterate over keys in current category
foreach fullKey $keys {
# Determinate key
regsub {^[^/]*/} $fullKey {} key
# Determinate value
set value [subst -nocommands "\$$configArray\(\$fullKey\)"]
regsub -all "\n" $value "\a" value
# Save key and value
puts $configFile "$key=\"$value\""
}
}
# Done ...
close $configFile
return 1
}
## Return True if config array is empty
# @return Bool - result
public method isEmpty {} {
return $isEmpty
}
## Return True if interface is ready
# @return Bool - result
public method isReady {} {
return $isReady
}
## Clear all settings
# @return void
public method clear {} {
array unset $configArray
}
## Remove specified key from settings
# @parm String key - name of key to remove
# @return Bool - result
public method remove {key} {
regsub -all {_} $key {__} key
regsub -all {\s} $key {_} key
if {[i_contains $key]} {
unset "$configArray\($key\)"
return 1
} else {
return 0
}
}
## Return True if the specified key is defined
# @parm String key - key to search for
# @return Bool - result
public method contains {key} {
regsub -all {_} $key {__} key
regsub -all {\s} $key {_} key
return [i_contains $key]
}
## Internal key search (Does not peform key name adjusment)
# @parm String key - name of key to search for
# @return Bool - result
private method i_contains {key} {
if {[array names $configArray -exact $key] == {}} {
return 0
} else {
return 1
}
}
## Get value for the given key
# @parm String key - Key
# @parm Mixed default - Default value
# @return Mixed - value for the given key
public method getValue {key default} {
# Adjust key name
if {![regexp {^.+/} $key]} {
set key "general/$key"
}
regsub -all {_} $key {__} key
regsub -all {\s} $key {_} key
# Check for valid key format
if {![regexp {^[\w:]+/[\w:]+$} $key]} {
return $default
}
# Check if the given key is defined
if {[i_contains $key]} {
return [subst -nocommands "\$$configArray\(\$key\)"]
} else {
return $default
}
}
## Set value for the given key
# @parm String key - Key
# @parm Mixed value - Value
# @return Bool - result
public method setValue {key value} {
## Check for key validity
if {[regexp {[\!\=\$\^\*\+\?\.\[\]\{\}\(\)]} $key]} {
return 0
}
regsub -all {_} $key {__} key
regsub -all {\s} $key {_} key
if {![regexp {^.+/} $key]} {
set key "general/$key"
}
if {![regexp {^[\w:]+/[\w:]+$} $key]} {
return 0
}
## Set value
set "$configArray\($key\)" $value
return 1
}
}
# >>> File inclusion guard
}
# <<< File inclusion guard
|