Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

how to update value of variable in file using tcl ?

90 views
Skip to first unread message

Nagesh HS

unread,
Jan 10, 2018, 2:40:15 AM1/10/18
to
Hi All,

I have 2 tcl file, in data.tcl file i am keeping flag bits and test.tcl file work based on the flag value . I need to reset the flag value in data.tcl after every test . could you please help me to do the same. I tried the following code but its not working


data.tcl :

set mac 1
set xmac 0
set fea 0

test.tcl :

set testcase mac

set fp [open "data.tcl" r+]

while { [gets $fp data] >= 0 } {
set var $data
if { [lindex $var 1] == $testcase } {
set fp1 [open "data.tcl" w+]
while { [gets $fp1 data1] >= 0 } {
set var1 $data1
if { [lindex $var1 1] == $testcase } {
set [lindex $var1 2] 0
}
close $fp1
}

close $fp
}
}

close $fp

Arjen Markus

unread,
Jan 10, 2018, 4:13:08 AM1/10/18
to
On Wednesday, January 10, 2018 at 8:40:15 AM UTC+1, Nagesh HS wrote:
> Hi All,
>
> I have 2 tcl file, in data.tcl file i am keeping flag bits and test.tcl file work based on the flag value . I need to reset the flag value in data.tcl after every test . could you please help me to do the same. I tried the following code but its not working

You are reading the file and at the same time you are writing it, that won't work indeed. But there is a simpler solution:
Since your data file is essentially Tcl code, you can simply source it - that gives you the current values, and then something like:

set $testcase 0

where I assume $testcase has been set to the name of the variable you need to reset.

I am not sure I comprehend your complete requirements, but I would do something along these lines.

Regards,

Arjen

stefan

unread,
Jan 10, 2018, 4:54:28 AM1/10/18
to
Hi Nagesh,

Like Arjen, I am not completely sure I can follow your requirements. From what I understood, I would use sth. along the lines of:

# ------------%<data.tcl>%----------
mac 1
xmac 1
fea 0

# ------------%< test.tcl >%----------

if {![file exists data.tcl] || ![file readable data.tcl]} {
return
}

set test mac

set fh [open data.tcl r]

try {
set data [read $fh]
set d [dict create {*}$data]
} finally {
close $fh
}

if {![info exists d] || ![dict size $d]} {
error "No test data."
}

## run your test case(s)

dict set d $test 0

set out [list]
dict for {key value} $d {
lappend out [list $key $value]
}


set fh [open data.tcl w]
try {
puts -nonewline $fh [join $out "\n"]
} finally {
close $fh
}

Some notes:

- [dict] helps preserve the order of entries in data.tcl
- You might get away with one [open], if you'd use [chan truncate] on an already opened channel (after the [read])
- All this can certainly be prettified, shortened.

HTH,
Stefan

Rich

unread,
Jan 10, 2018, 5:58:16 AM1/10/18
to
Arjen Markus <arjen.m...@gmail.com> wrote:
> On Wednesday, January 10, 2018 at 8:40:15 AM UTC+1, Nagesh HS wrote:
>> Hi All,
>>
>> I have 2 tcl file, in data.tcl file i am keeping flag bits and
>> test.tcl file work based on the flag value . I need to reset the
>> flag value in data.tcl after every test . could you please help me
>> to do the same. I tried the following code but its not working
>
> I am not sure I comprehend your complete requirements, but I would do
> something along these lines.

This posting smells suspiciously of a homework puzzle.

sled...@gmail.com

unread,
Jan 10, 2018, 3:55:27 PM1/10/18
to
::fileutil::updateInPlace ?options? file cmd
::fileutil::foreachLine var filename cmd

Use regsub to find\replace the string of code relating to the var you wish to update.

Nagesh HS

unread,
Jan 11, 2018, 2:04:15 AM1/11/18
to
Thank you all for your inputs, As few people mentioned that they are not clear about what I am looking for. so I am trying rewrite what exactly I am looking for.


I am writing automation script, where test runs if the particular flag bit is set to one in data.tcl file.
After completing the first task, I need to reset the MAC flag value to 0 and I need to set xmac flag file 1 and remaining flags to 0.

before running test script flag values in data.tcl

set mac 1
set xmac 0
set fea 0
set fea1 0

after 1st run: expected content of data.tcl file:

set mac 0
set xmac 1
set fea 0
set fea1 0

after 2nd run: expected content of data.tcl file:

set mac 0
set xmac 0
set fea 1
set fea1 0

after 3rd run: expected content of data.tcl file:

set mac 0
set xmac 0
set fea 0
set fea1 1

Hope you guys got my requirement.

lmn...@gmail.com

unread,
Jan 11, 2018, 6:11:43 PM1/11/18
to
You will need to open TWO channels to "modify the content of a file".
1. Open the original file "read access".
2. Open an output file "write access".

As you read the input file line by line, print the modifications to the output file.
If you need to replace the input file with the output file -- end the script with:
> file rename <name_of_output_file> <name_of_input_file>

OTHER SUGGESTIONS:


TCLTEST:
I would recommend looking into tcltest instead of writing your own test flow control program -- especially if what you're describing is something that will control test flow.

https://www.tcl.tk/man/tcl/TclCmd/tcltest.htm

Example Code:
The tcl source directory has tons of examples showing how to use tcltest.
It is an amazing place to ramp up quickly!

BUT WHAT IF I DONT USE TCLTEST?:
If, for whatever reason you want to continue developing your test package, I have two suggestions:

Suggestion 1:
Make data.tcl an array:

./data.tcl
array set test ""
set test(mac) 0
set test(xmac) 1
set test(fea) 0
set test(fea1) 0

If you need to preserver order -- add this:
set test(1,mac) 0
set test(2,xmac) 1
set test(3,fea) 0
set test(4,fea1) 0

Then simply source the file in your run.
> source data.tcl

And this gets you the current values of all variables and can be updated changed as needed.

Then simply write out the data file:

> set o [open data.tcl w]

> foreach arrayName [lsort -dictionary [array names test]] {
puts $o "set test($arrayName) $test($arrayName)"
}

> close $o

WHAT IF I HAVE OTHER CRITERIA?
If the criteria expands for what your assignment is -- like how to handle inserting tests or other features, skip tests, defining pass/fail criteria, etc -- you will quickly start reinventing 'tcltest' package and all of its magic -- so I would recommend going tcltest.

Suggestion 2:
As I look at your code, "I see" what might be a fundamantel question you have (not easy to see but after some thought) -- you might be hung up on automatically figuring out if a test has been added or changed, etc...

If that's the case - the concept you're looking for is: [info vars]
set init_vars [info_vars]
source data.tcl
set final_vars [info vars]
listcomp $final_vars $init_vars


Write yourself a little listcomp procedure (here you go):

./listcomp.tcl

proc listcomp {a b} {
# Be sure to pass the new list first (a) (larger of the two lists)
# followed by reference list (b)...
# because foreach only looks at (a) and if (a) is the smaller of the two lists, items in (b) will not be checked...
# Returns the difference/list
set diff {}
foreach i $a {
if {[lsearch -exact $b $i]==-1} {
lappend diff $i
}
}
return $diff
}

And now you know if/any new variables have been added.

You can also keep a record of old values and new values (enhance the code above), etc...

I think you're going to come back with, but..."what about this" and but..."what about that"...and keep expanding the actual criteria that you 'need' or 'want' -- whatever the case may be. You haven't shared if this is 'homework' or 'work'.
If this is 'work -- definitely go with 'tcltest' package!

But lets go down the rat hole a little more...

Suggestion 3:
Think about doing a csv structure in the data.tcl file instead of what you have now. This way as you loop through the file, it has a fixed structure, you can think about what other fields of information you want to have and have that part of the format and as you modify the file/contents on the fly this becomes easy(er).

FYI: I used the 'info vars' trick shown above to solve a 'big data' problem where I needed to source many tcl files (huge files) and bring that data into memory to work on (restore a design). So I read each file into a separate thread, leveraging tcl ::thread package and then brought the variables back to the main thread using tcl ::tsv (thread save variables).

There is a little bit of code (literally a little bit) that is required to send the variables back to the main/thread depending on if it's an array or scalar variable -- left as an exercise for the user or another post.

Jim
0 new messages