Extract the value of a variable that matches a pattern in TCL - tcl

I have a list called parameters and the content of this list can be different but it will look something like:
var1=2;
var2=2'h2;
var3=2'h0;
....
This list comes from reading a file and done some preformating already. I just want to grab the value of var1 and store it in a variable. Eg whatever is in between '=' sign and ';' sign but only for var1 (in this case number 2). Equally I can remove all the lines that are not matching 'var1'.

Assuming your parameters list is already set, you can do something like:
foreach item $parameters {
if {[regexp "var1\\s*=\\s*(\\w+);" $item wholeMatch myVal]} {
break
}
}
puts "value is '$myVal'"
The regular expression I use allows for optional spaces before and after the equal sign. Take a look at Tcl's regex syntax and adjust as necessary.
It might be easier to just do a regex search through your whole file using, rather than parsing your file into a list. But again, take a look at Tcl's documentation.

Related

apparent inconsistency read/write variable

I'm learning about Tcl just now. I've seen just a bit of it, I see for instance to create a variable (and initialize it) you can do
set varname value
I am familiarizing with the fact that basically everything is a string, such as "value" above, but "varname" gets kind of a special treatment I guess because of the "set" built-in function, so varname is not interpreted as a string but rather as a name.
I can later on access the value with $varname, and this is fine to me, it is used to specify varname is not to be considered as a string.
I'm now reading about lists and a couple commands make me a bit confused
set colors {"aqua" "maroon" "cyan"}
puts "list length is [llength $colors]"
lappend colors "purple"
So clearly "lappend" is another one of such functions like set that can interpret the first argument as a name and not a string, but then why didn't they make it llength the same (no need for $)?
I'm thinking that it's just a convention that, in general, when you "read" a variable you need the $ while you don't for "writing".
A different look at the question: what Tcl commands are appropriate for list literals?
It's valid to count the elements of a list literal:
llength {my dog has fleas}
But it doesn't make sense to append a new element to a literal
lappend {my dog has fleas} and ticks
(That is actually valid Tcl, but it sets the odd variable ${my dog has fleas})
this is more sensible:
set mydog {my dog has fleas}
lappend mydog and ticks
Names are strings. Or rather a string is a name because it is used as a name. And $ in Tcl means “read this variable right now”, unlike in some other languages where it really means “here is a variable name”.
The $blah syntax for reading from a variable is convenient syntax that approximately stands in for doing [set blah] (with just one argument). For simple names, they become the same bytecode, but the $… form doesn't handle all the weird edge cases (usually with generated names) that the other one does. If a command (such as set, lappend, unset or incr) takes a variable name, it's because it is going to write to that variable and it will typically be documented to take a varName (variable name, of course) or something like that. Things that just read the value (e.g., llength or lindex) will take the value directly and not the name of a variable, and it is up to the caller to provide the value using whatever they want, perhaps $blah or [call something].
In particular, if you have:
proc ListRangeBy {from to {by 1}} {
set result {}
for {set x $from} {$x <= $to} {incr x $by} {
lappend result $x
}
return $result
}
then you can do:
llength [ListRangeBy 3 77 8]
and
set listVar [ListRangeBy 3 77 8]
llength $listVar
and get exactly the same value out of the llength. The llength doesn't need to know anything special about what is going on.

Use of brackets and space character in Tcl

I am still confused about the usage of the bracket i.e () [] and {} use in Tcl. I always get caught out using the wrong bracket, having missed brackets when it was required to use them or having used too many of them. Besides this, I am also getting confused by Tcl giving me different result depending on presence or absence of space character (in math expression) and also if I have used more than one space character in succession.
Can someone please give me the basic rules that I must keep in mind to get out of this mess. Brackets have always been simple to use in C and some other languages but here they are totally different.
At the level you're looking at, Tcl is very different to any other language you've ever worked with. The heart of Tcl is defined by the Tcl(n) manual page, which states that (among other things):
Whitespace separates words. Every command takes its arguments as a sequence of words. Newlines and semicolons separate command calls; they're totally equivalent, but good style is to use a newline instead of a semicolon.
{braces} are used mainly for quoting text so that it is passed to commands with no substitutions or word separation performed on it. They nest properly. Braces are also used after $ to do variable substitution in a few cases: that's a rare use.
"double quotes" are used for quoting text so that it is passed to commands with substitutions applied, but no word separation.
[brackets] are a command substitution. They are replaced with the result of running the script inside the bracket. The script is usually a single command.
(parentheses) only have one base language use: for (associative) array elements. Thus, $a(b) is a variable substitution that will use the value of the b element in the a array.
The rest of what people call Tcl is really just a standard library, a set of commands to get you started. Some are fundamental. For example:
if is a conditional command, evaluating a branch (a script) if a condition is true. In order for this to be meaningful, the branch has to be not evaluated until the condition has been evaluated and tested; that pretty much requires putting it in braces.
while is a looping command, and not only do you want to brace its body (that's probably going to be evaluated over and over) but you also want to put the condition expression in braces as well as you definitely want that to be reevaluated each time round the loop.
proc is a command that makes your own custom commands. The body of the procedure definitely is something you want to evaluate later; it goes in braces.
expr is a general expression evaluation command. Under all normal circumstances, you'll want to put its expression in braces so that the code can be compiled and won't have double substitution problems. Note that expressions often make heavy use of parentheses: they have additional meanings in expression syntax. In particular, apart from being array element lookups, they're also used for function calls and grouping.
Note that if and while also use that same expression evaluation engine. They just use the result of the expression to decide what to do.
Scoping is a matter for commands to decide. The usual commands for dealing with introducing a scope are proc and namespace eval. This is nothing like C, C++, Java, C#, or Javascript; they have different rules. Variables are local to their procedure unless you explicitly say otherwise.
The community practice is to do calls like this:
if { $foo(bar) > (17 + $grill) * 7 } {
# This is a comment; it lasts to the end of the line
puts "the foobar $foo(bar) is too large"
set foo(bar) [ComputeSmallerValue $grill]
}
That is, barewords (if and puts) are unquoted, expressions and inner scripts are brace-quoted, parentheses are used where meaningful but most for arrays and expressions, whitespace separates all words, inner scripts are indented (usually by 4) for clarity (it doesn't have semantic meaning, but it sure helps with reading), and “blocks” use egyptian braces so that you don't have to add backslashes all over the place.
You don't have to follow these rules (they're guidelines, not the law) but they make your life easier if you do. Sometimes you do need to break the rules, but then you should know to be careful.
You cannot compare Tcl to C. In C, {} defines scope. In Tcl, {} is a grouping operator.
In Tcl, {} may group a string:
{hello world}
Or a list:
{a b c d e f g h}
Or a script:
{
puts -nonewline {hello }
puts world\n
}
Every command is simply a series of groups (which may be a word, a list,
an expression or a script):
{if} {true} { puts "hello\n" }
Of course, you don't need to put braces around every word,
but you do need braces to enclose a script:
if true { puts hello\n }
Generally, for the if statement, not bracing the expression is a bad idea,
so this is better:
if { true } { puts hello\n }
This simple rule creates Tcl's remarkably simple syntax. Every command is simply
a series of groups, whether a word, an expression, a list or script:
if expr script
while expr script
proc name argument-list script
puts string
for initialization condition nextloop script
The one important thing to remember is whenever an expression is wanted, it
should be enclosed within braces in order to prevent early substitution. e.g.:
set i 0
while { $i < 10 } {
incr i
}
The square brackets, [], are replaced with the output of a command enclosed
by the square brackets:
set output [expr {2**5}]
Parentheses are used within expressions as usual:
set output [expr {(2**5)+2}]
And for arrays:
set i 0
while { $i < 5 } {
set output($i) [expr {2**$i}]
incr i
}
parray output

How do I use the ternary operator to add an optional part to an anonymous string in tcl?

I am new to tcl (sorry if the answer is obvious, but reading tutorials and documentation did not help). I have a statement in tcl that says:
startupitem.start "foo
\tbar"
What I would like to do is have the "foo" part become optional, depending on the outcome of
[variant_isset "alice"] using the ternary operator and without using variables.
I've tried several things along the lines
startupitem.start "[variant_isset """alice"""?"""foo\n\t""":""""""] bar"
(of course with all kinds of escapes and combo's or the use of the double quotes inside the double quotes) but I haven't succeeded.
The outcome if the variant_isset expression returns true is that it is equivalent to
startupitem.start "bar"
You might prefer to use the if command (which is very much the command version of the ternary operator), whose result is the result of the body script it evaluates. If there isn't an else clause, the result is the empty string if nothing else is chosen to do:
startupitem.start "[if {[variant_isset alice]} {string cat "foo\n\t"}] bar"
Or you can build a list and then join it:
set items {}
if {[variant_isset alice]} {
lappend items "foo"
}
lappend items bar
startupitem.start [join $items "\n\t"]
This second approach tends to work particularly well when things get complicated.
You want to check out Tcl's expr command, which introduces Tcl's expression sub-language incl. what you call the "ternary" operator ?:
startupitem.start "[expr {[variant_isset "alice"] ? "foo\n\t" : ""}]bar"
If you happen to use a Tcl recent enough, you may want to prefer an outplace string assembly using string cat, rather than inplace:
string cat [expr {[variant_isset "alice"] ? "foo\n\t" : ""}] "bar"

Can we give array name with hyphen in TCL

I am declaring a array in TCL say
set JDSU-12-1(key) element
parray JDSU-12-1
I am getting error saying JDSU is not a array
Even simple puts statement is not working
% puts $JDSU-12-1(key)
can't read "JDSU": no such variable
Is there any way i can declare array name with hyphen. I know _ works in array but not sure about hyphen
You can use special characters in Tcl variable names. You need the braces for those though:
% puts ${JDSU-12-1(key)}
element
You can even use $:
% set \$word "Hello world" ;# Or set {$word} "Hello world"
% puts ${$word}
Hello world
EDIT: Some reference:
beedub.com (Emphasis mine)
The set command is used to assign a value to a variable. It takes two arguments: the first is the name of the variable and the second is the value. Variable names can be any length, and case is significant. In fact, you can use any character in a variable name.
You can use almost any character for the name of a variable in Tcl — the only restrictions relate to :: as that is a namespace separator, and ( as that is used for arrays — but the $ syntax is more restrictive; the name it accepts (without using the ${…} form) has to consist of just ASCII letters, ASCII digits, underscores or namespace separators. Dashes aren't on that list.
The standard (and simplest) way of reading from a variable with a “weird” name is to use set with only one argument, as that happily accepts any legal variable name at all:
puts "the element is '[set JDSU-12-1(key)]'"
However, if you're doing this a lot it is actually easier to make an alias to the (array) variable name:
upvar 0 JDSU-12-1 theArray
puts "the element is $theArray(key)"
That's exactly how parray does it, though it uses upvar 1 because it is aliasing to a variable in the calling scope and not in the current scope.
Although you can use such special characters, you can only use a few when you try to access variables with $varname.
To quote the relevant section from the manual:
$name
Name is the name of a scalar variable; the name is a sequence of one or more characters that are a letter, digit, underscore, or namespace separators (two or more colons). Letters and digits are only the standard ASCII ones (0-9, A-Z and a-z).
$name(index)
Name gives the name of an array variable and index gives the name of an element within that array. Name must contain only letters, digits, underscores, and namespace separators, and may be an empty string. Letters and digits are only the standard ASCII ones (0-9, A-Z and a-z). Command substitutions, variable substitutions, and backslash substitutions are performed on the characters of index.
${name}
Name is the name of a scalar variable or array element. It may contain any characters whatsoever except for close braces. It indicates an array element if name is in the form “arrayName(index)” where arrayName does not contain any open parenthesis characters, “(”, or close brace characters, “}”, and index can be any sequence of characters except for close brace characters. No further substitutions are performed during the parsing of name.
There may be any number of variable substitutions in a single word. Variable substitution is not performed on words enclosed in braces.
Note that variables may contain character sequences other than those listed above, but in that case other mechanisms must be used to access them (e.g., via the set command's single-argument form).
I want to empathis the last paragraph a bit:
You are always able to read any variable with set varname:
set JDSU-12-1(key) element
puts [set JDSU-12-1(key)]
Unlike the ${varname} access, you can substitute a part of the variable name (in your case the array key), the entire variable, while set k "key"; puts ${JDSU-12-1($k)} does not work.
You can easily do that:
set set-var "test"
while accessing so ${set-var}
Like in most other programming languages, TCL variable must be alphanumeric starting with letter (A to Z, or _). Hyphen or dash (-) is not permitted as part of variable name, otherwise it would be confused with arithmetic minus or subtraction: there would be no difference between $x-1 as variable with name "x-1" or $x-1 as variable x minus 1.
Try this :)
subst $\{[subst ${conn}](phan)\}
Which version are you working ??
my tcl works.
% set JDSU-12-1(key) element
element
% parray JDSU-12-1
JDSU-12-1(key) = element

How to search for pattern in multiple lines using a regular expression

Consider the pattern is:
PPP(GJ) {
__hj_o:
}
What is the regular expression match the above pattern?
Tcl's regular expressions can contain newlines just fine, but for anything complicated it can help to put it in its own variable instead of having it as an inline literal:
set RE {PPP(GJ) {
__hj_o:
}}
if {[regexp $RE $someString]} {
# We got a match!
}
Indeed, regexp would also match the above with this:
set RE {PPP(GJ)\s+{\s+__hj_o:\s+}}
because newlines are just ordinary whitespace characters (i.e., are matched by \s and .) by default. (The above REs are probably not exactly what you want; they likely need suitable patterns for the non-whitespace portions as well.)
However, you need to ensure that the string you are matching against has the whole thing that you want to match. If you're just feeding through one line at a time, that multiline pattern will consistently fail. This sounds obvious, but it is the easiest mistake to make.