Skip to content

Instantly share code, notes, and snippets.

@stephenmm
Created January 20, 2020 23:40
Show Gist options
  • Save stephenmm/6374ebff67a5538c9f2c2f0e6db0a198 to your computer and use it in GitHub Desktop.
Save stephenmm/6374ebff67a5538c9f2c2f0e6db0a198 to your computer and use it in GitHub Desktop.
Some basic utilities to .tcl a bit more bearable
proc xdbg { } { puts $::errorInfo }; # This must be the first proc and be as simple as possible so we are always able to debug
# Define required globals
set ::xhelpMsgs [dict create]
set ::xVerbosity INFO
# Define the verbosity levels (based on python logging levels: https://verboselogs.readthedocs.io/en/latest/readme.html )
set ::verbosityLevel [dict create]
dict append ::verbosityLevel NOTSET 0 ;# When a logger is created, the level is set to NOTSET (note that the root logger is created with level WARNING). This level isn?t intended to be used explicitly, however when a logger has its level set to NOTSET its effective level will be inherited from the parent logger.
dict append ::verbosityLevel DEVDBG 5 ;# Way too verbose for regular debugging, but nice to have when someone is getting desperate in a late night debugging session and decides that they want as much instrumentation as possible! :-)
dict append ::verbosityLevel DEBUG 10;# Detailed information, typically of interest only when diagnosing problems. Usually at this level the logging output is so low level that it?s not useful to users who are not familiar with the software?s internals.
dict append ::verbosityLevel VERBOSE 15;# Detailed information that should be understandable to experienced users to provide insight in the software?s behavior; a sort of high level debugging information.
dict append ::verbosityLevel INFO 20;# Confirmation that things are working as expected.
dict append ::verbosityLevel NOTICE 25;# Auditing information about things that have multiple success paths or may need to be reverted.
dict append ::verbosityLevel WARNING 30;# An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ?disk space low?). The software is still working as expected.
dict append ::verbosityLevel SUCCESS 35;# A very explicit confirmation of success.
dict append ::verbosityLevel ERROR 40;# Due to a more serious problem, the software has not been able to perform some function.
dict append ::verbosityLevel CRITICAL 50;# A serious error, indicating that the program itself may be unable to continue running.
############################################################# {{{
proc xargExists { flag args } {
set helpText "Help text for proc: xargExists
Purpose: Short and sweet way to test if optional args were passed in: '--this' or '--that=type'
It will be one of the first things done in a proc.
Usage: xargExists flag argsRef
Inputs: flag: Flag to test existance for in the 'args'
argsRef: The list of args
Outputs: Flag exists, return 1 if flag is found in args
Flag not exists, return 0 if flag is not found in args
Side Effects: None other than pass by value args
Optional Args: None
Examples: if { \[xargExists --verb args] } { set verbose 1 }
"
dict append ::xhelpMsgs xargExists $helpText
#puts "flag:$flag args:$args"
set expectVal 0
set cnt 0
if { [string first "=" $flag] != -1 } { set expectVal 1 }
foreach arg $args {
if { $expectVal==1 } {
lassign [regexp -inline -- "^($flag)(\\w+)$" $arg] all flagFound val
} else {
lassign [regexp -inline -- "^($flag)(=\\w+)?$" $arg] all flagFound val
}
#puts "all:$all\t flagFound:$flagFound\t val:$val"
if { $flagFound != {} } { incr cnt }
}
return $cnt
}
proc _test_proc_xargExists {} {
proc _argExists_test { sigWithHier args } {
puts "sigWithHier:$sigWithHier\t args:$args"
puts [xargExists --val $args]
puts [xargExists --vala $args]
puts [xargExists --val= $args]
puts [xargExists --vala= $args]
}
_argExists_test hier.with.--sig --val
_argExists_test hier.with.--sig --val=1
_argExists_test hier.with.--sig --vala
_argExists_test hier.with.--sig --vala=2
}
############################################################# }}}
############################################################# {{{
proc xputs { level str args } {
set helpText "
Purpose: Adding basic verbosity around .tcl puts. With the default level set to INFO
Usage: xputs <level> <string> \[<args>]
Inputs: level: In priority order: NOTSET DEVDBG DEBUG VERBOSE INFO NOTICE WARNING SUCCESS ERROR CRITICAL
string: string to print
Outputs: Retruns dict prvInf that contains information about the prove run
Side Effects: Creates sim directory and logs. Consumes CPU time and fpv licenses. Can be blocking or non-blocking
Optional Args: --help - Prints this help message.
--set_verbosity - Sets the minimum level that will be printed.
Examples: xputs INFO 'this would get printed by default'
xputs WARNING {} --set_verbosity
xputs INFO 'now you would not see this msg'
"
dict append ::xhelpMsgs xputs $helpText
if { [xargExists --help args] } { xhelp xputs; return 0; }
if {![dict exists $::verbosityLevel $level]} {
error "level:$level Is not a valid xverbosity level. Please use a valid level:"
foreach lvl [dict keys $::verbosityLevel] { puts -nonewline "$lvl,"; }
}
if { [xargExists --set_verbosity args] } { set ::xVerbosity [dict get $::verbosityLevel $level]; }
if { [dict get $::verbosityLevel $level] >= $::xVerbosity } {
puts "(XPUTS:$level) $str"
}
return $::xVerbosity
}
############################################################# }}}
############################################################# {{{
proc xargPop { flag rtrnVar args } {
set helpText "Help text for proc: xargPop
Purpose: Short and sweet way to process proc args: '--this' or '--that=type'
It will be one of the first things done in a proc.
Usage: xargPop flag rtrnRef argsRef
Inputs: flag: Flag to find in args (extract value) and remove from args
rtrnRef: If --arg=val return the val in this reference
argsRef: The list of args
Outputs: Return the number of time flag was found in args (zero if not found)
Side Effects: Removes --falg from args reference
Optional Args: None
Examples: set verbose \[xargPop --verbose {} args] ;# Will set verbose to the number of times --verbose passed in
set tsk dfltTask; xargPop --setTask= tsk args
"
dict append ::xhelpMsgs xargPop $helpText
upvar $args upvarArgs
xputs DEVDBG "xargPop(1010): flag:$flag\t rtrnVar:$rtrnVar\t upvarArgs:$upvarArgs"
if { $rtrnVar != {} } { upvar $rtrnVar upvarRtrnVal }
set expectVal 0
set i 0
set cnt 0
set delArgIdxs [list]
if { [string first "=" $flag] != -1 } { set expectVal 1 }
foreach arg $upvarArgs {
if { $expectVal==1 } {
lassign [regexp -inline -- "^($flag)(\\w+)$" $arg] all flagFound val
} else {
lassign [regexp -inline -- "^($flag)(=\\w+)?$" $arg] all flagFound val
}
xputs DEVDBG "xargPop(1020): arg:$arg\t all:$all\t flagFound:$flagFound\t val:$val"
if { $flagFound != {} } {
incr cnt
if { $rtrnVar != {} } { set upvarRtrnVal $val }
lappend delArgIdxs $i
}
incr i
}
xputs DEVDBG "xargPop(1030): args:$args\t upvarArgs:$upvarArgs\t rtrnVar:$rtrnVar"
foreach i [lreverse $delArgIdxs] {
set upvarArgs [lreplace $upvarArgs $i $i]
}
xputs DEVDBG "xargPop(1040): args:$args\t upvarArgs:$upvarArgs\t rtrnVar:$rtrnVar"
return $cnt
}
proc _test_proc_argPop {} {
proc _argPop_test { sigWithHier args } {
puts "_argPop_test(100):sigWithHier:$sigWithHier\t args:$args"
set myval {}
set argsCp $args
set rtn [xargPop --val {} argsCp]
puts "_argPop_test(101): $rtn myval: $myval args:$args argsCp:$argsCp"
set argsCp $args
set rtn [xargPop --val myval argsCp]
puts "_argPop_test(102): $rtn myval: $myval args:$args argsCp:$argsCp"
set argsCp $args
set rtn [xargPop --vala {} argsCp]
puts "_argPop_test(103): $rtn myval: $myval args:$args argsCp:$argsCp"
set argsCp $args
set rtn [xargPop --vala myval argsCp]
puts "_argPop_test(104): $rtn myval: $myval args:$args argsCp:$argsCp"
set argsCp $args
set rtn [xargPop --val= {} argsCp]
puts "_argPop_test(105): $rtn myval: $myval args:$args argsCp:$argsCp"
set argsCp $args
set rtn [xargPop --val= myval argsCp]
puts "_argPop_test(106): $rtn myval: $myval args:$args argsCp:$argsCp"
set argsCp $args
set rtn [xargPop --vala= {} argsCp]
puts "_argPop_test(107): $rtn myval: $myval args:$args argsCp:$argsCp"
}
_argPop_test hier.with.--sig --val
_argPop_test hier.with.--sig --val=1
_argPop_test hier.with.--sig --vala
_argPop_test hier.with.--sig --vala=2
_argPop_test hier.with.--sig --val=3 --val=4
_argPop_test hier.with.--sig --val=5 --vala=6 --val
}
############################################################# }}}
############################################################# {{{
proc xhelp { { prc {} } { str {} } } {
if {[string trim $prc] == ""} {
set helpText "Help text for proc: xhelp
Purpose: Procedure to display help for crus_utils_fv procs
Usage: xhelp \[<procName>] \[<helpString>]
Inputs: No inputs are required
Outputs: Retruns number of help msgs if successfully added or retrived help, 0 otherwise
Side Effects: Can append to ::xhelp
Optional Args: ProcName: The name of the procedure to display help on
helpString: Register new help msg (for advanced users only)
Examples: xhelp ;# Displays this msg and 'Purpose:' for procs that registered with xhelp
xhelp x_prove;# Displays help for x_prove
xhelp --add='Text to help end users'
"
puts -nonewline "$helpText"
puts "\nShort description/purpose for each of the procs that have help strings:"
foreach p [dict keys $::xhelpMsgs] {
set fullMsg [dict get $::xhelpMsgs $p]
lassign [regexp -inline -- "Purpose: +(\[^\\n]+)\\n" $fullMsg] fullMatch shortMsg
puts " $p purpose:\t$shortMsg";
}
puts " "
} elseif { $prc == "--add" } {
# store a new help msg
set prc [lindex [info level -1] 0];# get the caller proc name
if {![dict exists $::xhelpMsgs $prc]} {
dict append ::xhelpMsgs $prc $str
} else {
puts "ERROR: trying to add a msg for a proc that already has one $prc"
return 0
}
} else {
# Display proc help msg
if {[dict exists $::xhelpMsgs $prc]} {
puts "Help text for proc: $prc"
puts [dict get $::xhelpMsgs $prc]
} else {
puts "ERROR: No help msg is registered for the proc: $prc"
return 0
}
}
return [dict size $::xhelpMsgs]
}
############################################################# }}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment