jmerkow
jmerkow

Reputation: 1860

get global tcl array in python or c++

I need to import existing information from tcl files (saved variables in tcl) but I am not familiar with tcl really at all. I need a simple solutions (short), it does not need to be super robust. I have a tcl file that defines a global. Here is a small snippet:

test.tcl:

global gP
set gP(1,1) {-2.77577 -2.66083 14.6978}
set gP(1,2) {-2.2751 -1.91189 13.5285}
set gP(1,3) {-1.46855 -1.21695 11.8953}
...
set gP(1,spline) [list \
  {p (-0.005623,0.225326,4.821360) t (-0.155507,0.806054,-0.571047) tx (0.000000,0.578079,0.815981)} \{p (-0.006889,0.231865,4.816766) t (-0.156976,0.809595,-0.565609) tx (0.000000,0.572709,0.819758)} \
...
  {p (2.224570,6.136620,-6.119510) t (0.901583,0.422393,0.093441) tx (0.000000,0.215995,-0.976394)} \
  ]
...
set gP(1,4) {-0.673205 -0.728409 10.3576}
set gP(1,5) {-0.261822 -0.476418 9.47673}
set gP(1,name) {path1}
...

What I want to do is run tcl from either python or c++ to produce gP in that language. So something like (in python:)

from Tkinter import Tcl
MYFILE = 'test.tcl'
tcl = Tcl()
gP = tcl.evalfile(MYFILE)

My end goal is to get this into c++, but I don't need all of gP. One problem I ran into doing this so far, is that gP is an array, and therefore will not return in the normal way in Tkinter.

This doesn't need to be elegant, I'll only use this once or twice. I am willing to manipulate the variable in python, print out just what I need in a text (or CSV) file, then read that into c++ to populate a variable.

EDIT

Doing this as patthoyts described is a really great start! I think I need one (or two levels of parsing?

I have done this (gPathPoints and gP are the same, different varname only):

a  = eval(tcl.eval('''set r {};
  foreach k [array names gPathPoints] {
    lappend r "'$k': '$gPathPoints($k)'"
  };
  set r "{[join $r ,]}"
  '''))

Python spits out a decent dictionary, but the keys are a little funky:

'100,0': '-2.939 -3.02 15.136',
'100,1': '-2.77577 -2.66083 14.6978',
'100,10': '-0.00681104 0.408274 3.53018',
...

I can probably figure this out with a simple c++ method but I think the following would be easier in tcl:

'100,spline': '{p (-2.939000,-3.020000,15.136000) t (0.242924,0.657821,-0.712923) tx (0.000000,0.734938,0.678134)} {p (-2.934674,-3.008616,15.123467) t (0.250593,0.647200,-0.719955) tx (0.000000,0.743684,0.668531)}

Upvotes: 1

Views: 1146

Answers (1)

patthoyts
patthoyts

Reputation: 33203

Using python:

from Tkinter import *
# create an array in tcl
tk.eval('array set a {a 1 b 2 c 3 d "4 5 6"}')
s = tk.eval('array get a')

This returns the array as a string but using tcl list formatting: 'd {4 5 6} a 1 b 2 c 3' so you need to re-parse this a bit. You can turn it into a python dict by doing that parsing in Tcl quite easily:

a  = eval(tk.eval('''set r {};
  foreach k [array names a] {
    lappend r "'$k': '$a($k)'"
  };
  set r "{[join $r ,]}"
  '''))

using the above example code this yields:

>>> a
{'a': '1', 'c': '3', 'b': '2', 'd': '4 5 6'}
>>> a['d']
'4 5 6'
>>>

You'd have to be more careful about the quoting handling if the array values have embedded quotes but thats simple enough as well.

In C++ I think you may as well evaluate array get $varname to get a Tcl list object. Then you can iterate over the list of key value pairs using Tcl_ListObjGetElements and related functions.

Upvotes: 3

Related Questions