blob: b7361beb4cc55bac0d1394d7ac997f14d6e43054 [file] [log] [blame]
Michael Walsh768c1302018-02-15 17:17:55 -06001#!/usr/bin/wish
2
3# This file provides many valuable validation procedures such as valid_value,
4# valid_integer, etc.
5
6my_source [list print.tcl call_stack.tcl]
7
8
9proc valid_value { var_name { invalid_values {}} { valid_values {}} } {
10
11 # If the value of the variable named in var_name is not valid, print an
12 # error message and exit the program with a non-zero return code.
13
14 # Description of arguments:
15 # var_name The name of the variable whose value is to
16 # be validated.
17 # invalid_values A list of invalid values. If the variable
18 # value is equal to any value in the
19 # invalid_values list, it is deemed to be
20 # invalid. Note that if you specify
21 # anything for invalid_values (below), the
22 # valid_values list is not even processed.
23 # In other words, specify either
24 # invalid_values or valid_values but not
25 # both. If no value is specified for either
26 # invalid_values or valid_values,
27 # invalid_values will default to a list with
28 # one blank entry. This is useful if you
29 # simply want to ensure that your variable
30 # is non blank.
31 # valid_values A list of invalid values. The variable
32 # value must be equal to one of the values
33 # in this list to be considered valid.
34
35 # Call get_stack_var_level to relieve the caller of the need for declaring
36 # the variable as global.
37 set stack_level [get_stack_var_level $var_name]
38 # Access the variable value.
39 upvar $stack_level $var_name var_value
40
41 set len_invalid_values [llength $invalid_values]
42 set len_valid_values [llength $valid_values]
43
44 if { $len_valid_values > 0 && $len_invalid_values > 0 } {
45 append error_message "Programmer error - You must provide either an"
46 append error_message " invalid_values list or a valid_values"
47 append error_message " list but NOT both.\n"
48 append error_message [sprint_list invalid_values "" "" 1]
49 append error_message [sprint_list valid_values "" "" 1]
50 print_error_report $error_message
51 exit 1
52 }
53
54 if { $len_valid_values > 0 } {
55 # Processing the valid_values list.
56 if { [lsearch -exact $valid_values "${var_value}"] != -1 } { return }
57 append error_message "The following variable has an invalid value:\n"
58 append error_message [sprint_varx $var_name $var_value "" "" 1]
59 append error_message "\nIt must be one of the following values:\n"
60 append error_message [sprint_list valid_values "" "" 1]
61 print_error_report $error_message
62 exit 1
63 }
64
65 if { $len_invalid_values == 0 } {
66 # Assign default value.
67 set invalid_values [list ""]
68 }
69
70 # Assertion: We have an invalid_values list. Processing it now.
71 if { [lsearch -exact $invalid_values "${var_value}"] == -1 } { return }
72
73 if { [lsearch -exact $valid_values "${var_value}"] != -1 } { return }
74 append error_message "The following variable has an invalid value:\n"
75 append error_message [sprint_varx $var_name $var_value "" "" 1]
76 append error_message "\nIt must NOT be one of the following values:\n"
77 append error_message [sprint_list invalid_values "" "" 1]
78 print_error_report $error_message
79 exit 1
80
81}
82
83
84proc valid_integer { var_name } {
85
86 # If the value of the variable named in var_name is not a valid integer,
87 # print an error message and exit the program with a non-zero return code.
88
89 # Description of arguments:
90 # var_name The name of the variable whose value is to
91 # be validated.
92
93 # Call get_stack_var_level to relieve the caller of the need for declaring
94 # the variable as global.
95 set stack_level [get_stack_var_level $var_name]
96 # Access the variable value.
97 upvar $stack_level $var_name var_value
98
99 if { [catch {format "0x%08x" "$var_value"} result] } {
100 append error_message "Invalid integer value:\n"
101 append error_message [sprint_varx $var_name $var_value]
102 print_error_report $error_message
103 exit 1
104 }
105
106}
107
108
109proc valid_dir_path { var_name { add_slash 1 } } {
110
111 # If the value of the variable named in var_name is not a valid directory
112 # path, print an error message and exit the program with a non-zero return
113 # code.
114
115 # Description of arguments:
116 # var_name The name of the variable whose value is to
117 # be validated.
118 # add_slash If set to 1, this procedure will add a
119 # trailing slash to the directory path value.
120
121 # Call get_stack_var_level to relieve the caller of the need for declaring
122 # the variable as global.
123 set stack_level [get_stack_var_level $var_name]
124 # Access the variable value.
125 upvar $stack_level $var_name var_value
126
127 expand_shell_string var_value
128
129 if { ![file isdirectory $var_value] } {
130 append error_message "The following directory does not exist:\n"
131 append error_message [sprint_varx $var_name $var_value "" "" 1]
132 print_error_report $error_message
133 exit 1
134 }
135
136 if { $add_slash } { add_trailing_string var_value / }
137
138}
139
140
141proc valid_file_path { var_name } {
142
143 # If the value of the variable named in var_name is not a valid file path,
144 # print an error message and exit the program with a non-zero return code.
145
146 # Description of arguments:
147 # var_name The name of the variable whose value is to
148 # be validated.
149
150 # Call get_stack_var_level to relieve the caller of the need for declaring
151 # the variable as global.
152 set stack_level [get_stack_var_level $var_name]
153 # Access the variable value.
154 upvar $stack_level $var_name var_value
155
156 expand_shell_string var_value
157
158 if { ![file isfile $var_value] } {
159 append error_message "The following file does not exist:\n"
160 append error_message [sprint_varx $var_name $var_value "" "" 1]
161 print_error_report $error_message
162 exit 1
163 }
164
165}
Michael Walsh05296fb2018-03-02 15:39:21 -0600166
167
168proc get_password { {password_var_name password} } {
169
170 # Prompt user for password and return result.
171
172 # On error, print to stderr and terminate the program with non-zero return
173 # code.
174
175 set prompt\
176 [string trimright [sprint_varx "Please enter $password_var_name" ""] "\n"]
177 puts -nonewline $prompt
178 flush stdout
179 stty -echo
180 gets stdin password1
181 stty echo
182 puts ""
183
184 set prompt [string\
185 trimright [sprint_varx "Please re-enter $password_var_name" ""] "\n"]
186 puts -nonewline $prompt
187 flush stdout
188 stty -echo
189 gets stdin password2
190 stty echo
191 puts ""
192
193 if { $password1 != $password2 } {
194 print_error_report "Passwords do not match.\n"
195 gen_exit_proc 1
196 }
197
198 if { $password1 == "" } {
199 print_error_report "Need a non-blank value for $password_var_name.\n"
200 gen_exit_proc 1
201 }
202
203 return $password1
204
205}
206
207
208proc valid_password { var_name { prompt_user 1 } } {
209
210 # If the value of the variable named in var_name is not a valid password,
211 # print an error message and exit the program with a non-zero return code.
212
213 # Description of arguments:
214 # var_name The name of the variable whose value is to
215 # be validated.
216 # prompt_user If the variable has a blank value, prompt
217 # the user for a value.
218
219 # Call get_stack_var_level to relieve the caller of the need for declaring
220 # the variable as global.
221 set stack_level [get_stack_var_level $var_name]
222 # Access the variable value.
223 upvar $stack_level $var_name var_value
224
225 if { $var_value == "" && $prompt_user } {
226 global $var_name
227 set $var_name [get_password $var_name]
228 }
229
230 if { $var_value == "" } {
231 print_error_report "Need a non-blank value for $var_name.\n"
232 gen_exit_proc 1
233 }
234
235}
236
237
238proc process_pw_file_path {pw_file_path_var_name} {
239
240 # Process a password file path parameter by setting or validating the
241 # corresponding password variable.
242
243 # For example, let's say you have an os_pw_file_path parm defined. This
244 # procedure will set the global os_password variable.
245
246 # If there is no os_password program parm defined, then the pw_file_path
247 # must exist and will be validated by this procedure. If there is an
248 # os_password program parm defined, then either the os_pw_file_path must be
249 # valid or the os_password must be valid. Again, this procedure will verify
250 # all of this.
251
252 # When a valid pw_file_path exists, this program will read the password
253 # from it and set the global password variable with the value.
254 # Finally, this procedure will call valid_password which will prompt user
255 # if password has not been obtained by this point.
256
257 # Description of argument(s):
258 # pw_file_path_var_name The name of a global variable that
259 # contains a file path which in turn
260 # contains a password value. The variable
261 # name must end in "pw_file_path" (e.g.
262 # "os_pw_file_path").
263
264 # Verify that $pw_file_path_var_name ends with "pw_file_path".
265 if { ! [regexp -expanded "pw_file_path$" $pw_file_path_var_name] } {
266 append message "Programming error - Proc [get_stack_proc_name] its"
267 append message " pw_file_path_var_name parameter to contain a value that"
268 append message "ends in \"pw_file_path\" instead of the current value:\n"
269 append message [sprint_var pw_file_path_var_name]
270 print_error $message
271 gen_exit_proc 1
272 }
273
274 global $pw_file_path_var_name
275 expand_shell_string $pw_file_path_var_name
276
277 # Get the prefix portion of pw_file_path_var_name which is obtained by
278 # stripping "pw_file_path" from the end.
279 regsub -expanded {pw_file_path$} $pw_file_path_var_name {} var_prefix
280
281 # Create password_var_name.
282 set password_var_name ${var_prefix}password
283 global $password_var_name
284
285 global longoptions pos_parms
286 regsub -all ":" "${longoptions} ${pos_parms}" {} parm_names
287 if { [lsearch -exact parm_names $password_var_name] == -1 } {
288 # If no corresponding password program parm has been defined, then the
289 # pw_file_path must be valid.
290 valid_file_path $pw_file_path_var_name
291 }
292
293 if { [file isfile [set $pw_file_path_var_name]] } {
294 # Read the entire password file into a list, filtering comments out.
295 set file_descriptor [open [set $pw_file_path_var_name] r]
296 set file_data [list_filter_comments [split [read $file_descriptor] "\n"]]
297 close $file_descriptor
298
299 # Assign the password value to the global password variable.
300 set $password_var_name [lindex $file_data 0]
301 # Register the password to prevent printing it.
302 register_passwords [set $password_var_name]
303 }
304
305 # Validate the password, which includes prompting the user if need be.
306 valid_password $password_var_name
307
308}