TCL, get full error message in catch command - error-handling

#!/usr/bin/tclsh
proc test {} {
aaa
}
test
When I run this script I get error message:
invalid command name "aaa"
while executing
"aaa"
(procedure "test" line 2)
invoked from within
"test"
(file "./a.tcl" line 7)
If I run test command in catch I get only first line of error message.
#!/usr/bin/tclsh
proc test {} {
aaa
}
catch test msg
puts $msg
This prints:
invalid command name "aaa"
Is it possible to get full error message (file, line, procedure) in catch command? My program has many files and by getting just one line of error message it is difficult to find from where is it.

The short answer is to look at the value of errorInfo which will contain the stack trace.
The more complete answer is to look at the catch and the return manual pages and make use of the -optionsVarName parameter to the catch statement to collect the more detailed information provided. The return manual page gives some information on using this. But a rough example from an interactive session:
% proc a {} { catch {funky} err detail; return $detail }
% a
-code 1 -level 0 -errorstack {INNER {invokeStk1 funky} CALL a} -errorcode NONE -errorinfo {invalid command name "funky"
while executing
"funky"} -errorline 1
%
The detail variable is a dictionary, so use dict get $detail -errorinfo to get that particular item.

Related

How to make if else checkbox enabled/disabled in sql query and asp.net?

I want to make my checkbox is enabled and disable when user login from my data
My syntaks in asp.net:
if (Session["Berhasil"] != null)
{
Label1.Visible = true;
Label1.Text = "Berhasil..";
if(Label1 = "select * from cs100020 where countno=2 and status=3");
{
cbxinven.Enabled=true
cbxfinadmin.Enabled=true
cbxkaskecil.Enabled=true
cbxemail.Enabled=false
cbxsap.Enabled=false
cbxpc.Enabled=false
cbxuserad.Enabled=false
}
else (Label1="select * from cs100020 where countno=3 and status=3);
{
cbxinven.Enabled=false
cbxfinadmin.Enabled=false
cbxkaskecil.Enabled=false
cbxemail.Enabled=true
cbxsap.Enabled=true
cbxpc.Enabled=true
cbxuserad.Enabled=true
}
}
and i got error :
Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS1010: Newline in constant
Source Error:
Line 137: cbxuserad.Enabled=false
Line 138: }
Line 139: else (Label1="select * from cs100020 where countno=3 and status=3);
Line 140: {
Line 141: cbxinven.Enabled=false
Source File: d:\Sharing\Budiman\IAPHRM BACKUP 08022019\IapHRM_180119_Backup\ViewCS.aspx.cs Line: 139
Show Detailed Compiler Output:
Show Complete Compilation Source:
The closing double quote on the SQL statement for the ELSE branch (i.e. else (Label1 = .... line) is missing.

What is the exception that should be thrown when user input is blank?

I've been searching for some time now, and I'm sure I've missed it, is there any documentation that states what should be thrown when a value is incorrect/blank?
For example, Python has ValueError and the documentation clearly states when to use it.
I have the following method:
proc getJobinfo {question} {
puts -nonewline "$question: "
flush stdout
gets stdin answer
set cleanedanswer [string trim [string totitle $answer]]
if {$cleanedanswer eq ""} {
# What error should be thrown?
}
return $cleanedanswer
}
I've searched throw, error, and catch, but couldn't find it.
Tcl doesn't have a pre-defined hierarchy of exceptions. The throw command takes 2 arguments: type is a list of words; and message is an error message for humans.
You could do something like
proc getJobinfo {question} {
...
if {$cleanedanswer eq ""} {
throw {Value Empty} "Please provide a suitable answer."
} elseif {[string length $cleanedanswer] < 5} {
throw {Value Invalid} "Your answer is too short."
} else ...
return $cleanedanswer
}
If you want to trap that error:
try {
set answer [getJobinfo "What is the answer to this question"]
} trap {Value *} msg {
puts "Value Error: $msg"
}
throw and try interact via the type words of the throw call. We throw "Value Empty" or "Value Invalid". In the trap, we match Value exactly, but we won't match * exactly. In hindsight the * should not be there.
The try manpage is not super clear at first read:
trap pattern variableList script
This clause matches if the evaluation of body resulted in an error and the prefix of the -errorcode from the interpreter's status dictionary is equal to the pattern. The number of prefix words taken from the -errorcode is equal to the list-length of pattern, and inter-word spaces are normalized in both the -errorcode and pattern before comparison.
pattern is not a pattern in the regexp or string match sense: it's a list of words that is matched one-by-one with the list of words thrown in the try body.
The try can be implemented with multiple traps to have cascading "catches":
try {
set answer [getJobinfo "What is the answer to this question"]
} trap {Value Empty} msg {
do something specific here
} trap {Value Invalid} msg {
do something specific here
} trap {Value} msg {
do something general for some other "throw {Value anything} msg"
} on error e {
this can be default catch-all for any other error
} finally {
any cleanup code goes here
}

try and ignore errors in my tcl command

Hi I am new to tcl and I am trying to run a command in a for loop, while this command does what it needs to do, but, it throws an exception, which causes the loop to break. So, I need to ignore any error that is produced by this command and still try the command each time in my for loop.
for loop {
#do some stuff
$chassis exportPacketTrace $new_name -compress false 1 2 both #try this but ignore its error and continue
#do some stuff
}
Please help me with a good solution for this problem
if {[catch {$chassis exportPacketTrace $new_name -compress false 1 2 both} issue]} {
puts "There is a failure and it is ignored"
puts "Reason for failure : $issue"
}
Reference : catch

Rancid/ Looking Glass perl script hitting an odd error: $router unavailable

I am attempting to set up a small test environment (homelab) using CentOS 6.6, Rancid 3.1, Looking Glass, and some Cisco Switches/Routers, with httpd acting as the handler. I have picked up a little perl by means of this endeavor, but python (more 2 than 3) is my background. Right now, everything on the rancid side of things works without issue: bin/clogin successfully logs into all of the equipment in the router.db file, and logging of the configs is working as expected. All switches/routers to be accessed are available and online, verified by ssh connection to devices as well as using bin/clogin.
Right now, I have placed the lg.cgi and lgform.cgi files into var/www/cgi-bin/ which allows the forms to be run as cgi scripts. I had to modify the files to split on ';' instead of ':' due to the change in the .db file in Rancid 3.1:#record = split('\:', $_); was replaced with: #record = split('\;', $_); etc. Once that change was made, I was able to load the lgform.cgi with the proper router.db parsing. At this point, it seemed like everything should be good to go. When I attempt to ping from one of those devices out to 8.8.8.8, the file correctly redirects to lg.cgi, and the page loads, but with
main is unavailable. Try again later.
as the error, where 'main' is the router hostname. Using this output, I was able to find the function responsible for this output. Here it is before I added anything:
sub DoRsh
{
my ($router, $mfg, $cmd, $arg) = #_;
my($ctime) = time();
my($val);
my($lckobj) = LockFile::Simple->make(-delay => $lock_int,
-max => $max_lock_wait, -hold => $max_lock_hold);
if ($pingcmd =~ /\d$/) {
`$pingcmd $router`;
} else {
`$pingcmd $router 56 1`;
}
if ($?) {
print "$router is unreachable. Try again later.\n";
return(-1);
}
if ($LG_SINGLE) {
if (! $lckobj->lock("$cache_dir/$router")) {
print "$router is busy. Try again later.\n";
return(-1);
}
}
$val = &DoCmd($router, $mfg, $cmd, $arg);
if ($LG_SINGLE) {
$lckobj->unlock("$cache_dir/$router");
}
return($val);
}
In order to dig in a little deeper, I peppered that function with several print statements. Here is the modified function, followed by the output from the loaded lg.cgi page:
sub DoRsh
{
my ($router, $mfg, $cmd, $arg) = #_;
my($ctime) = time();
my($val);
my($lckobj) = LockFile::Simple->make(-delay => $lock_int,
-max => $max_lock_wait, -hold => $max_lock_hold);
if ($pingcmd =~ /\d$/) {
`$pingcmd $router`;
} else {
`$pingcmd $router 56 1`;
}
print "About to test the ($?) branch.\n";
print "Also who is the remote_user?:' $remote_user'\n";
print "What about the ENV{REMOTE_USER} '$ENV{REMOTE_USER}'\n";
print "Here is the ENV{HOME}: '$ENV{HOME}'\n";
if ($?) {
print "$lckobj is the lock object.\n";
print "#_ something else to look at.\n";
print "$? whatever this is suppose to be....\n";
print "Some variables:\n";
print "$mfg is the mfg.\n";
print "$cmd was the command passed in with $arg as the argument.\n";
print "$pingcmd $router\n";
print "$cloginrc - Is the cloginrc pointing correctly?\n";
print "$LG_SINGLE the next value to be tested.\n";
print "$router is unreachable. Try again later.\n";
return(-1);
}
if ($LG_SINGLE) {
if (! $lckobj->lock("$cache_dir/$router")) {
print "$router is busy. Try again later.\n";
return(-1);
}
}
$val = &DoCmd($router, $mfg, $cmd, $arg);
if ($LG_SINGLE) {
$lckobj->unlock("$cache_dir/$router");
}
return($val);
}
OUTPUT:
About to test the (512) branch.
Also who is the remote_user?:' '
What about the ENV{REMOTE_USER} ''
Here is the ENV{HOME}: '.'
LockFile::Simple=HASH(0x1a13650) is the lock object.
main cisco ping 8.8.8.8 something else to look at.
512 whatever this is suppose to be....
Some variables:
cisco is the mfg.
ping was the command passed in with 8.8.8.8 as the argument.
/bin/ping -c 1 main
./.cloginrc - Is the cloginrc pointing correctly?
1 the next value to be tested.
main is unreachable. Try again later.
I can provide the code for when DoRsh is called, if necessary, but it looks mostly like this:&DoRsh($router, $mfg, $cmd, $arg);.
From what I can tell the '$?' special variable (or at least according to
this reference it is a special var) is returning the 512 value, which is causing that fork to test true. The problem is I don't know what that 512 means, nor where it is coming from. Using the ref site's description ("The status returned by the last pipe close, backtick (``) command, or system operator.") and the formation of the conditional tree above, I can see that it is some error of some kind, but I don't know how else to proceed with this inspection. I'm wondering if maybe it is in response to some permission issue, since the remote_user variable is null, when I didn't expect it to be. Any guidance anyone may be able to provide would be helpful. Furthermore, if there is any information that I may have skipped over, that I didn't think to include, or that may prove helpful, please ask, and I will provide to the best of my ability
May be you put in something like
my $pingret=$pingcmd ...;
print 'Ping result was:'.$pingret;
And check the returned strings?

How to set default values for Tcl variables?

I have some Tcl scripts that are executed by defining variables in the command-line invocation:
$ tclsh84 -cmd <script>.tcl -DEF<var1>=<value1> -DEF<var2>=<value2>
Is there a way to check if var1 and var2 are NOT defined at the command line and then assign them with a set of default values?
I tried the keywords global, variable, and set, but they all give me this error when I say "if {$<var1>==""}": "can't read <var1>: no such variable"
I'm not familiar with the -def option on tclsh.
However, to check if a variable is set, instead of using 'catch', you can also use 'info exist ':
if { ![info exists blah] } {
set blah default_value
}
Alternatively you can use something like the cmdline package from tcllib. This allows you to set up defaults for binary flags and name/value arguments, and give them descriptions so that a formatted help message can be displayed. For example, if you have a program that requires an input filename, and optionally an output filename and a binary option to compress the output, you might use something like:
package require cmdline
set sUsage "Here you put a description of what your program does"
set sOptions {
{inputfile.arg "" "Input file name - this is required"}
{outputfile.arg "out.txt" "Output file name, if not given, out.txt will be used"}
{compressoutput "0" "Binary flag to indicate whether the output file will be compressed"}
}
array set options [::cmdline::getoptions argv $sOptions $sUsage]
if {$options(inputfile) == ""} {puts "[::cmdline::usage $sOptions $sUsage]";exit}
The .arg suffix indicates this is a name/value pair argument, if that is not listed, it will assume it is a binary flag.
You can catch your command to prevent error from aborting the script.
if { [ catch { set foo $<var1> } ] } {
set <var1> defaultValue
}
(Warning: I didn't check the exact syntax with a TCL interpreter, the above script is just to give the idea).