US 2003-04-10
#
# "fulfills" checks a string against a regular expression and
# a couple of criteria. It returns 1, if the regular expression
# matches and all criteria are fulfilled, else returns 0.
#
# It is useful for the check of test results,
# or for evaluation of reports.
#
# The first argument is the string to be checked
# The second argument is a regex to split string into substrings
# (it defaults to .* that matches the entire string)
#
# If the given regex is incorrect, "fulfills" throws an error
#
# All following args contain criteria, that apply to the respective
# substring, the first to everything the regex matches, the second
# to the first parenthized subexpression,... (see regexp man page)
#
# "fulfills" returns a truth value as follows:
#
# regexp doesn't match --> 0
# more criteria given than substrings delivered by regexp --> 0
#
# Criteria:
#
# An empty criterium means "don't check this substring" and evals to "true".
# /string/ --> string match against "string"
# %string% --> string match against "string" -nocase
# ~string~ --> string equal "string" -nocase
# =string= --> string equal "string"
#
# If the criterium begins with one of the following, it uses expr to check.
# -eq --> numerical check: substring is equal
# -gt --> numerical check: substring is greater than
# -lt --> numerical check: substring is less than
# -ne --> numerical check: substring is not equal
# -ge --> numerical check: substring is greater or equal
# -le --> numerical check: substring is less or equal
# These criteria may contain placeholders of the form @1 ... @9 which
# expand to the corresponding substring.
# -- --> expr evals substring to a truth value
#
# Any criterium, that doesn't have one of the forms described above,
# evals "string equal criterium substring"
#
# Evaluation stops with first false value
# If the string fulfills all criteria, "fulfills" returns 1.
#
# Note, that the regex and the criteria must be quoted, if they
# contain whitespace or special characters.
#
proc fulfills {str {re .*} args} {
set matcher [list regexp "$re" $str]
set n 0
foreach arg $args {
lappend matcher p($n)
incr n
}
if {[catch $matcher result]} {
} else {
if {!$result} {return 0}
}
set tv 1
set n 0
foreach arg $args {
if {![string length $arg]} {
# empty arg, always true
continue
}
if {![string length $p($n)]} {
# empty subexpr, always false
set tv 0
break
}
set f [string index $arg 0]
set m [string range $arg 1 end-1]
set l [string index $arg end]
switch -- $f {
/ {
if {[string equal $f $l]} {
# string match
set tv [string match $m $p($n)]
} else {
# string equal
set tv [string equal $arg $p($n)]
}
}
% {
if {[string equal $f $l]} {
# string match
set tv [string match -nocase $m $p($n)]
} else {
# string equal
set tv [string equal $arg $p($n)]
}
}
= {
# string equal
if {[string equal $f $l]} {
# string equal
set tv [string equal $m $p($n)]
} else {
# string equal
set tv [string equal $arg $p($n)]
}
}
~ {
if {[string equal $f $l]} {
# string match
set tv [string equal -nocase $m $p($n)]
} else {
# string equal
set tv [string equal $arg $p($n)]
}
}
- {
# expr check
regsub -all {@([1-9])} [string range $arg 3 end] \$p(\\1) ec
switch -glob -- $arg {
-- {
set e "($p($n)) != 0"
}
-eq* {
set e "($p($n)) == ($ec)"
}
-ne* {
set e "($p($n)) != ($ec)"
}
-gt* {
set e "($p($n)) > ($ec)"
}
-ge* {
set e "($p($n)) >= ($ec)"
}
-lt* {
set e "($p($n)) < ($ec)"
}
-le* {
set e "($p($n)) <= ($ec)"
}
default {
set e [string equal $arg $p($n)]
}
}
if {[catch "expr $e" tv]} {
# error in expr
puts "error in expr $e --- $tv"
}
}
default {
# string equal
set tv [string equal $arg $p($n)]
}
}
if {!$tv} break
incr n
}
return $tv
}
# Examples (uncomment to try):
#
# puts "[fulfills abc\$123 {abc\$([0-9]+)$} /a*/ /*2*/ c d e f]"
# puts "[fulfills abc\$123 {abc\$([0-9]+)$} /a*/ /*2*/]"
# puts "[fulfills abc123 {abc([0-9]+)} a b]"
# puts "[fulfills Abc123 {Abc([0-9]+)} %a*% 123]"
# puts "[fulfills Abc123 {Abc([0-9]+)} %a*% -eq123]"
# puts "[fulfills Abc123 {Abc([0-9]+)} %a*% "-lt 200"]"
# puts "[fulfills Abc123 {Abc([0-9]+)} %a*% "-ge 200"]"
# puts "[fulfills Abc123 {Abc([0-9]+)} %a*% -123]"
# puts "[fulfills Abc123 {Abc([0-9]+)} %a*% -a23]"
# puts "[fulfills Abc1+2+3 {^Abc(.+)$} %a*% --]"
# puts "[fulfills Abc1+2-3 {^Abc(.+)$} %a*% --]"
# puts "[fulfills Abc1+2-3 {^Abc(.+)$} %a*% -lt@1+1]"
# puts "[fulfills Abc1+2x3 {^Abc(.+)x([0-9])$} %a*% -lt5 -eq@1]"
# puts "[fulfills Abc123]"
#