Display permanently current time in Tcl - tcl

I have three questions, all of them closely related to each other. The most important one is the first one.
First: I am trying to display the current time in the format hours:minutes:seconds, so
set systemTime [clock seconds]
puts "The time is: [clock format $systemTime -format %H:%M:%S]"
But the above clock should be permanently updated, that is, the seconds-part of the clock should be running all the time.
Second: In the next step I would like to display milliseconds and they should be updated as well.
Third: I would like to execute a procedure at a certain point of time. More precisely: At a certain time, say 16:20 (the format here is hours:minutes), tcl musst execute a procedure, say proc SumUpInt, which I defined. It may be possible that I want to consider seconds and milliseconds as well when executing the proc.
I do not know how to do this. I have found many similar questions on some web sites, also on stack overflow, but I was not able to adapt some of these solutions to my problem.
Any help is welcome!
Thank you in advance.

There doesn't seem to be an output directive in clock format for milliseconds, so perhaps:
proc timestamp {} {
set t [clock milliseconds]
set systemTime [expr {int($t / 1000)}]
set milliSeconds [expr {$t % 1000}]
return [format "%s.%03d" [clock format $systemTime -format %T] $milliSeconds]
}
timestamp ;# => 14:41:13.032
You can turn this "realtime" with
proc run_timestamp {} {
puts -nonewline "\r[timestamp] "
flush stdout
after 100 run_timestamp
}
run_timestamp
vwait forever
But the vwait means this will block the Tcl interpreter. I don't have any thoughts right now about how to integrate this into your terminal.

Related

How to run repeatedly a proc in Tcl

I have written a proc in tcl which takes one argument (a positive integer) und displays a text. Lets call it permu (for permutation). I would like to execute this proc permanently, so
puts [permu 3]
and with the same argument (here 3), lets say every 2 or 3 seconds or so, without removing the previous outcome of the code. How can I do this?
The second question: Same question as above but I would like to clear the screen when the new outcome of permu is displayed.
Third question: In case that I decide to stop a running code (I work with Linux), for example the one above, how can I do this?
Thanks in advance!
Here's one way to do the repeated output:
proc repeat_permu {arg delay} {
puts [permu $arg]
after $delay [list repeat_permu $arg $delay]
}
# Note that the delay is in milliseconds
repeat_permu 3 3000
# Now start the event loop
vwait forever
To clear the screen you need to send the appropriate escape sequence before each new output. Most terminal emulators will accept the vt100 code, so you would do puts "\x1b[2J".
Normally you could just stop your program running by typing control-c, or do you want some means of doing this programmatically?
Update: A simpler way to do the repetition if you don't need to process any other events in parallel is just: while 1 {puts [permu 3]; after 3000}

Create a new file every time a TCL script runs

I am new to TCL and got some stuff I need to automate and I need my code to log all the commands and results after the login process.
My main issue is that I need to create a distinct log file everytime I run the script and one way I found out was to "append" the unique "timestamp" to the file name.
Here is where it starts to get picky, you see, every time I try to append the variable "$time" to the filename it returns:
couldn't open "15-10-28/11:57:10--xxx.xxxx.xxxx.txt": no such file or directory
while executing
"log_file "$newfile" "
(file "ssh-test.tcl" line 31)
My code is as follows:
set user [lrange $argv 0 0]
set password [lrange $argv 1 1]
set ipaddr [lrange $argv 2 2]
set arg1 [lrange $argv 3 3]
set systemTime [clock seconds]
set time [clock format $systemTime -format %y-%m-%d/%H:%M:%S--]
set a "ssh"
set suffix ".txt"
append newfile "${a}${arg1}${suffix}"
set timeout -1
# now connect to remote UNIX box (ipaddr) with given script to execute
spawn ssh $user#$ipaddr
match_max 100000
# Look for passwod prompt
expect "*?assword:*"
# Send password aka $password
send -- "$password\r"
log_file "$newfile" ;
expect "*#"
send -- "\r"
send_user "This is the $argv0 Script"
send -- "scm $arg1\r"
expect "*#"
send -- "exit\r"
expect eof
If I use the 'set filename "${a}${arg1}${suffix}"' string and 'log_file "$filename"' it works just fine but it will append the new info to the already existing file and I want a new file everytime I run the script.
If I use the 'append newfile "${a}${arg1}${suffix}"' string and 'log_file "$newfile"' it won't work and return the error already referred.
Hope you guys can help me out and thanks in advance for any support.
You are creating the timestamp with / in it.
set time [clock format $systemTime -format %y-%m-%d/%H:%M:%S--]
While appending this to the variable newfile, it will become 15-10-28/11:57:10--xxx.xxxx.xxxx.txt.
Expect will think that there is a folder called 15-10-28 available and under which I have to create the file 11:57:10--xxx.xxxx.xxxx.txt. Since that folder is not available, you are getting the error message as no such file or directory
After figuring out that the date format was messing up my code, I started playing around with the special characters and got it working like this:
set time [clock format $systemTime -format %a_%b_%d_%Y#%H'%M'%S]
It is not the desired format but at least I got it working as I intended.

TCL command wrapping

I am trying to write a TCL proc that will allow me to wrap statements and then 'execute' them internally.
For example, if I originally have :
set var $tmp
I want to have some procedure :
proc wrapper {command} {
puts "do something here"
puts $command #ie below : write "set var $tmp" to stdout
EXECUTE COMMAND HERE
puts "do something else here"
}
set void [wrapper {set var $tmp}]
My motivation is that I'm trying to write my own timing/profiler for individual statements.
Instead of "EXECUTE COMMAND", use
uplevel 1 $command
Note that if you attempt to time a script using a command like your wrapper, it won't be byte-compiled, which means that it won't perform the way it would inside a procedure.
Documentation: uplevel
You can give a try with time command which is already available with Tcl if your only intention is to just get the time taken by a set of code to execute.
time script ?count?
This command will call the Tcl interpreter count times to evaluate script (or once if count is not specified). It will then return a string of the form
503.2 microseconds per iteration
which indicates the average amount of time required per iteration, in microseconds. Time is measured in elapsed time, not CPU time.
Example :
set code_block {
foreach x "1 2 3" {
set y [expr {$x*20}];
}
}
puts [time $code_block 10]; # Executing the code for 10 times
which might produce random outputs such as
11.9 microseconds per iteration
Update 1 :
If you want to print the commands along with execution which is also possible. You can override the time command with rename command.
rename time _time; # Changing the 'time' to '_time'
# Defining your own 'time' command
proc time {command {count 1}} {
# Printing the commands here
puts $command
# Calling the actual '_time' command
# and returning that value from here
return [_time $command $count]
}
Place the above code at the top of your code and usage of time command after this will be using our customized procedure only.
They are passed as set of command which in turn, yes, a string. But, while the evaluation of the code, it will behave as if like how it will work in a tclsh.
As answered by Mr.Peter, if your code involves accessing the previous level of commands, variables, then you have to use uplevel or upvar based on your needs.
Reference : time, rename

How can I modify this eggdrop TCL script to work a little differently

I'm trying to set up a simple eggdrop bot to give a countdown til a certain event. The idea is that I give it a predetermined date and time, the user types !countdown and the bot replies with "There are x days, x hours, x minutes until it happens". This is the script as I found it (changed only to add the event's unixtime date in place of what it had), and running it on my eggdrop bot gives a response, but of course it isn't the response I needed (the important thing is that it worked at all).
I don't think there's a big difference between what it does and what I want it to do, but I have no idea how to correctly modify it. So I wondered if anyone here could show me how to do what I'm trying to do.
bind pub - !test countdown
proc countdown { nickname hostname handle channel arg } {
set date1 "1385798400"
# finds the time and date now
set now [unixtime]
# counts the time passed scince now
incr now -$date1
# shows how long has passed since $date1
set then [duration $now]
puthelp "PRIVMSG $channel :date1 was: $then ago, $nickname | \([\
clock format $date1 -format %d.%m.%Y] # [\
clock format $date1 -format %H:%M:%S]\)"
}
The hard part of working with dates is parsing and formatting, but you've already got utility commands to do that (duration and clock format). To work out the time remaining to an event in the future, you've just got to make sure that you do timestampfuture event - timestampnow in your calculations.
proc countdown {nickname hostname handle channel arg} {
set date1 "1385798400"
# finds the time and date now
set now [unixtime]
set left [duration [expr {$date1 - $now}]]
# Easier to store complex stuff in a variable and substitute stuff in
set formatted [clock format $date1 -format "(%d.%m.%Y # %H:%M:%S"}]
puthelp "PRIVMSG $channel :date1 will be: $left in the future, $nickname | $formatted"
}
Just bind that and off you go.

How can I create an RFC 3339 timestamp in TCL?

I inherited a TCL script (I have zero familiarity with the language) and need to add an RFC 3339 timestamp to it:
2012-04-05T12:13:32.123456-08:00
After searching Google, I haven't found any means of displaying the microseconds or the timezone offset (I have found a way to show the timezone name, but that doesn't help).
Is there a way to do this without calling an external process?
In TCL8.5, you can try the following command:
% clock format [clock seconds] -format "%Y-%m-%dT%T%z"
2012-04-05T16:06:07-0500
That gives you everything except the sub-second resolution. The clock microseconds command will give you the time in microseconds, but I can't find a format string identifier that matches it. You can use this to build your own command from scratch:
proc timestamp_rfc3339 {} {
set us [clock microseconds]
set sec [expr {$us / 1000000}]
set micro [expr {$us % 1000000}]
set ts [clock format $sec -format "%Y-%m-%dT%T"]
regexp {(...)(..)} [clock format $sec -format "%z"] matched tzh tzm
return [format "%s.%06s%s:%s" $ts $micro $tzh $tzm]
}
Running this results in a timestamp like 2012-04-05T16:35:06.366378-05:00.
Edit: Updated code sample to incorporate user1179884's tweaks (see comments) and to wrap in a proc.