Pages

Sunday, March 11, 2012

TCL Exam

1) What is the command to print a line of text?
  A) puts
  B) printf
  C) print

2) What may words be grouped with?
  A) Curly brackets -- {}
  B) Single Quotes -- ''
  C) Curly brackets or double quotes -- {} or ""

3) What character starts a comment?
  A) The semicolon -- ;
  B) The asterisk -- *
  C) The number sign -- #
  D) A smiley  :-)

1) You must declare the type of a variable in Tcl
  A) True
  B) False

2) The "set" command creates a variable and assigns it a value
  A) True
  B) False

3) The "puts" command will:
  A) put a value into a variable.
  B) put a variable into memory
  C) print a string to the standard output.

4) What will this script print:
set x "test"
puts x
  A) test
  B) x
  C) test x

5) What is the final value of the variable "a":
set a 1
set a "two"
  A) two
  B) 1
  C) generates an error

1) The dollarsign in "$i" means:
  A) use the value of the variable "i".
  B) that "i" is an integer variable.
  C) that "i" is a string variable.

2) What will this script output?
set i 100.00
puts "\$$i"
  A) a syntax error.
  B) $100.00
  C) $i

3) What will this script output:
set i 10
set j "The value of i is"
puts "$j $i"
  A) "$i $j"
  B) "i j"
  C) The value of i is 10

4) A double quote means
  A) group a set of words and variables into a single unit.
  B) evaluate a set of numbers and symbols mathematically.
  C) there are no variables in a set of words.

1) The primary difference between quote (") and curly braces ({}) is
  A) quotes allow special characters to be substituted and braces do not.
  B) quotes group strings and curly braces group lists.
  C) quotes can only be used for alphabetic characters, braces for numbers.

2) What will this script output?
set i 100.00
puts {\$$i}
  A) $100.00
  B) syntax error
  C) \$$i

3) What will this script output:
set x {I like "quotes"}
puts $x
  A) I like quotes
  B) I like "quotes"
  C) {I like "quotes"}

4) What will this script output:
set x "I like "quotes""
puts $x
  A) error - extra quotes
  B) I like "quotes"
  C) I like quotes

5) What will this script output:
set x {I like {braces}}
puts $x
  A) error - nested braces
  B) I like {braces}
  C) I like braces

1) Square brackets will group a set of words
  A) and allow substitutions.
  B) disable any special character processing.
  C) evaluate those words as a Tcl command.

2) What will be the value of "y" after this command is evaluated:
set y [set x 33]
  A) 33
  B) x
  C) [set x 33]

3) What will be the value of "y" after this command is evaluated:
set y {[set x 33]}
  A) 33
  B) x
  C) [set x 33]

4) Which command will assign the same value to "x" and "y"
  A) set x 33; set x $y
  B) set y [set x 33]
  C) set x,y 33

1) The "expr" command will
  A) evaluate an expression arithmetically.
  B) evaluate a Tcl expression.
  C) convert a boolean expression to English.

2) The "expr" command
  A) only works with integers.
  B) includes trigonometric and exponential functions.
  C) can parse words like "one" and "deux" into numbers.

3) What will be the value of x after this script is evaluated:
set x {expr [2+2]}
  A) no output - syntax error.
  B) 4
  C) {expr [2+2]}

4) Which command will assign the value 4 to the variable "x":
  A) set x [expr 2+2]
  B) set x "expr 2+2"
  C) set x {expr 2+2}

5) What will be the result of x after this script is evaluated:
set x 2
set x [expr $x+$x]
  A) 4
  B) 6
  C) 8
1) The "switch" command will
  A) switch the contents of two variables.
  B) evaluate the script associated with a value that matches a pattern.
  C) switch a variable between two values.

2) What will this script output when it is evaluated:
set x 1
switch $x {
  0 {puts a}
  1 {puts b}
  2 {puts c}
}
  A) "b"
  B) "1"
  C) No output - syntax error.

3) When the switch command finds a pattern that matches a test value
  A) it evaluates the script associated with that pattern.
  B) it evaluates all scripts following that pattern.
  C) it evaluates all scripts except the script associated with that pattern.

4) A "switch" command
  A) can have a "default" pattern to match if no other pattern matches.
  B) only use character strings for patterns.
  C) only use numeric strings for patterns.
1) The "if" command will
  A) evaluate an associated script if the test is false.
  B) evaluate an associated script if the test is true.
  C) select one of several options.

2) An "if" script can have
  A) only one "elseif" associated with it.
  B) multiple "else" statements associated with it.
  C) multiple "elseif" statements associated with it.

3) When an "if" test is false and there is no "else" or "elseif"
  A) the interpreter generates an error condition.
  B) the interpreter continues to the next line.
  C) the user is asked for input.

4) What will this script output when it is evaluated?
set x 3
if {$x > 4} {
  puts "$x is bigger than 4"
}
  A) 3 is bigger than 4
  B) nothing
  C) 3 is smaller than 4

5) What will this script output when it is evaluated?
set x 3; set y 4
if {($x+$y) == 7} {
  puts "lucky 7"
}
  A) lucky 7
  B) nothing
  C) syntax error

1) The "while" command
  A) will loop N times if the initial test is true.
  B) will loop as long as a test fails.
  C) will loop until a test fails.

2) What will this script output when it is evaluated:
set x 1
while {$x < 10} {
  puts "X: $x"
  set y [expr $x + 1]
}
  A) an infinite number of "X: 1" lines.
  B) lines from "X: 1" to "X: 9"
  C) lines from "X: 1" to "X: 10"

3) You should use a looping construct
  A) instead of repeating identical commands in a script.
  B) to reduce the number of lines the interpreter needs to process.
  C) whenever a script is over 100 lines long.

4) How many times with this loop iterate:
set x 0
while {$x < 10} {
  puts $x
  set x [expr $x+1]
}
  A) 9 times
  B) 10 times
  C) 11 times

1) To perform the same operation for values from 1 to 10
  A) use the foreach command.
  B) use the for command.
  C) use the do-while command.

2) How many times is the "start" script in a for loop evaluated:
  A) Once, before the body is evaluated.
  B) Once, after the first pass through the body.
  C) Every time the body is evaluated.

3) What will be the value of "total" after this code runs:

for {set total 1; set count 1} {$count < 3} {incr count} {
  set total [expr {$total + $total}]
}

  A) 1
  B) 2
  C) 4

4) The "test" script is evaluated:
  A) Once when the script starts
  B) On each pass, before evaluating the body
  C) On each pass, after evaluating the body

5) The "while" command
  A) is best when you want to loop until a condition occurs.
  B) is best when you want to loop on each element in a list.
  C) is best when you want to loop for each value between two integers.

1) Internal commands (like for) are handled differently from user defined commands.
  A) True
  B) False

2) The "proc" command
  A) Defines a procedure interface
  B) Defines a new procedure
  C) Is a pre-processor macro
  D) Defines and executes a procedure

3) You should consider using a procedure if a set of code is
  A) copied more than once
  B) copied more than twice
  C) copied more than three times

4) Using procedures
  A) Makes code more readable
  B) Makes code more re-usable
  C) Simplifies debugging
  D) All of the above

5) The "return" command will
  A) Return to the original code without evaluating the procedure
  B) Return a value from a procedure
  C) Insert a carriage return into an output stream

1) What is the default value for "b" in this procedure:
proc demo {a {b 2} {c 3} } {...}
  A) 3
  B) 2
  C) None

2) How many arguments does this procedure require:
proc demo {args one two} {...}
  A) 3
  B) any number
  C) 4

3) What will this procedure do:
proc foo {args} {
  set t 0
  foreach n $args {
    incr t $n
  }
  return $t
}
  A) Count the number of elements in a list.
  B) Return the total of a set of floating point numbers.
  C) Return the total of a set of integers.

4) To create a procedure that may accept two argument,
and has a default value of "2" if only one argument is defined,
which command is correct:
  A) proc {b 2 a} {...}
  B) proc {a {b 2}} {...}
  C) proc {a b 2} {...}
  D) proc {{a required} {b default 2}} {...}

1) When you call a command like this:
set i 1
command $i
  A) It is "call by name"
  B) It is a syntax error
  C) It is "call by value"

2) If you call a command like this:
set i 1
command i

  A) It is "call by name"
  B) It is a syntax error
  C) It is "call by value"

3) The upvar command will

  A) Map a variable from the calling scope into the local procedure scope.
  B) Map a variable from the local scope into the calling scope.
  C) Copy the value of a variable from the calling scope to the local scope.

4) What will be the value of i after this code is evaluated:

proc inc {nm} {
  upvar $nm x
  incr x
}
set i 2
inc i
  A) 4
  B) 3
  C) 2

5) What will be the value of i after this code is evaluated:

proc inc {nm} {
  incr nm
}
set i 2
inc $i
  A) 3
  B) 2
  C) 4

6) The "global" command
  A) maps a variable from the global scope into the procedure scope and gives it a unique name.
  B) maps a variable from the global scope into the procedure scope retaining the original name.
  C) makes a global-scope variable automatically map into all procedures.

1) Which of these commands assigns a list to the variable "lst"
  A) set lst "a b c"
  B) set lst {a b c}
  C) set lst [list a b c]
  D) All of the above

llength {this {is a} list}
  A) 1
  B) 2
  C) 3
  D) 4

3) Which command will return the first element of a list
  A) lindex $lst 0
  B) lindex $lst 1
  C) lindex $lst first

4) What will be the contents of lst after this command:
set lst [split "commas,can,delimit elements" ,]
  A) commas can delimit elements
  B) commas can {delimit elements}
  C) commas can delimit,elements

5) The quickest way to iterate through the elements of a list is to
  A) use the "foreach" command.
  B) use the "for" and "lindex" commands
  C) use the "while" command

1) What is the result of
concat a {b c} d
  A) a {b c} d
  B) {a {b c} d}
  C) a b c d

2) What are the contents of "lst" after this script is evaluated:
set lst {}
lappend lst a {b c} d
  A)  a b c d
  B) a {b c} d
  C) {a b c d}

3) What are the contents of "lst" after this script is evaluated:
set lst {a {b c} d}
set lst [linsert lst 1 e]
  A) a b c d e
  B) a e {b c} d
  C) lst e

4) What are the contents of "lst" after this script is evaluated:
set lst {a {b c} d}
set lst [lreplace $lst 1 1 e]
  A) a {b c} e
  B) a e d
  C) e {b c} d

5) What are the contents of "lst" after this script is evaluated:
set lst {a {b c} d}
set lst [lreplace $lst 1 1]
  A) a d
  B) {b c} d
  C) a {b c} d


1) What is returned by this code:
set lst {a b c d}
lsearch $lst a
  A) 0
  B) 1
  C) 2

2) Which code snippet will sort the list {a b c A B C} into {A a B b C c}?
  A) lsort {a b c A B C}
  B) lsort -dictionary {a b c A B C}
  C) lsort -decreasing {a b c A B C}

3) What will be the contents of lst after this script is evaluated:
set lst {1 2 3 4 5}
set lst [lrange $lst 1 3]
  A) 1 2 3
  B) 2 3 4 5
  C) 2 3 4

4) Which command will return 1?
  A) lsearch {aa bb cc dd} b
  B) lsearch {aa bb cc dd} b*
  C) lsearch {aa bb cc dd} [a-b]
  D) lsearch {aa bb cc dd} b??

1) What will this command return:
string length {12 34}
  A) 3
  B) 4
  C) 5

2) Which command will return "2"
  A) string index "12 34" 1
  B) string index "12 34" 0
  C) string index "12 34" 2

3) What will this command return:
string range "1234567" 1 5
  A) 12345
  B) 23456
  C) 123456

4) What is the index of the first character in a string?
  A) 0
  B) 1
  C) begin

5) Which script will return "5"
  A) string index 12345 5
  B) string index 12345 end
  C) string index 12345 last

1) Which script returns true?
  A) string compare "abc" "abc"
  B) string match "abc" "a*"
  C) string equal "abc" "abc"

2) Which script returns 2?
  A) string first 3 "123"
  B) string first "123" 2
  C) string first 2 "1234"

3) When might you use "string compare".
  A) When checking strings for equality.
  B) When sorting a set of strings.
  C) All of the above.

4) Which script will return 4
  A) string first 4 "0123401234"
  B) string last 4 "0123401234"
  C) string range "0123401234" 3 3

5) Which script will return true:
  A) string match "abc" "a*"
  B) string match "a*" "abc"
  C) string equal "a*" "abc"
  D) string match "a?" "abc"

6) What will this script return:
set st "this is a test"
string range $st [string wordstart $st 5] [string wordend $st 5]
  A) " is "
  B) "is"
  C) "is "
  D) " is"

1) The %6.2f option to format will print
  A) a six digit floating point number with 2 digits to the right of the decimal
  B) a five digit floating point number with 2 digits to the right of the decimal
  C) at least 6 spaces for a number 3 (or more) to the left of the decimal and 2 to the right

2) What value will end up in str when this script is evaluated:
set str "abcabcabc"
set str [string trim $str ca]
  A) bcabcab
  B) bbb
  C) bcabcb

3) Which command will strip trailing spaces, but leave leading spaces.
  A) string trimleft
  B) string trimright
  C) string trim

4) To capitalize a word use:
  A) string toupper
  B) string totitle
  C) string capitalize

1) The "glob" rules use a "*" to match any number of any character.
How do you identify any number of any characters with regexp?
  A) *
  B) +
  C) .*
  D) ?

2) The glob rules use a ? to match a single character.
How do you identify a single characters with regexp?
  A) .
  B) *
  C) ?
  D) +

3) Which regular expression would identify all letters between "a" and "m"?
  A) [am]
  B) [a-m]
  C) [am]*
  D) [a-m]*

4) Which string would match the regular expression A+B+
  A) AAaaBBbb
  B) CCAABBDD
  C) BBB
  D) BBAA

5) What is the value of m2 after this code is evaluated?
set l {Regular expressions are useful and powerful}
regexp {(e.*s)} $l m1 m2
  A) egular expressions
  B) e us
  C) egular expressions are us
  D) NO MATCH

6) What will end up in the variables b and c
set str "better tests choose correctly"
regexp {(b.*)(c.*)} $str a b c
  A) b: "better tests choose corre" c: "ctly"
  B) b: "better tests " c: "choose correctly"
  C) b: "better tests choose " c: "correctly"

7) Which test would assign "choose correctly" to variable c?
set str "better tests choose correctly"
regexp $test $str a b c
  A) set test {(b.*)(c.*)}
  B) set test {(b[^c]*)(c.*)}
  C) set test {(b.*)(co.*)}

1) What will be the contents of "findings" after this script is evaluated:
set str "better tests choose correctly"
foreach test [list {b[^ ]*} {c[^ ]*} {d[^ ]*} ] {
  if {[regexp $test $str word]} {
    lappend findings $word
  }
}
  A) better choose
  B) b c
  C) better choose correctly

2) Will the following script produce the same results?
set str "better tests choose correctly"
foreach l {a b c d} {
  if {[regexp "$l\[^ ]*" $str word]} {
    lappend findings $word
  }
}
  A) No
  B) Yes

3) Will the following script produce the same results as the previous script?
(The difference is quoting around the test)
set str "better tests choose correctly"
foreach l {a b c d} {
  if {[regexp {$l\[^ ]*} $str word]} {
    lappend findings $word
  }
}
  A) No
  B) Yes

4) If you use a quoted string, instead of a curly-braced string as a
test with regexp
  A) you must backslash escape parentheses and square braces
  B) you must backslash escape square braces
  C) you must backslash escape dollar signs in front of variable names

5) What will this script do:
set french {amusant est tres }
set english {fun is great}
set str "Tcl is great fun"
foreach f $french e $english {
  regsub $e $str $f str
}
  A) Convert "Tcl is great fun" to "amusant est tres Tcl"
  B) Nothing
  C) Translate "Tcl is great fun" to "Tcl est tres amusant"

1) You can tell if a variable is an array because
  A) It will have an index in parentheses.
  B) It will have an index in square brackets.
  C) It will have an index in curly braces.

2) Tcl arrays
  A) Must be indexed with an integer.
  B) Must use an integer greater than 0 as index.
  C) Can use any character or set of characters as the index.

3) The "array exists" command will
  A) return True if the name is an array or a procedure that returns an array.
  B) only return True if a variable is an array.
  C) return false if an array has only one index.

4) The "array names" command
  A) returns a list of unused names that can be used with an array.
  B) returns a list of array indices that match an optional pattern.
  C) returns a list of array indices who's associated values match a pattern.

5) The "array set" command
  A) Returns the intersection of two arrays.
  B) Assigns values to an array where indices match a pattern
  C) Assigns an arrays indices and associated values.

6) What does this script do:
array set xx {a 1 b 2 c 3}
array set yy [array get xx]
  A) Assigns the same values to xx and yy.
  B) Assign "xx" to yy.
  C) set xx(a) to "1" and yy(1) to "a".

7) The "array size" command will
  A) return the largest value in an array.
  B) return the largest index in an array.
  C) return the number of elements in an array.

8) An associative array is useful
  A) to collect related data under a single name.
  B) to simplify your code and reduce potential bugs.
  C) when you don't know the data set your code will work with until run time.
  D) all of the above.
  E) none of the above.

9) Which script will display only books written by Mark Twain:
array set books {
    Twain "Tom Sawyer"
    Twain "Huck Finn"
    Welch "Practical Programming in Tcl/Tk"
    Flynt "Tcl/Tk: A Developer's Guide"}
  A) foreach in [array names books] {puts $books($in)}
  B) foreach in [array names books T*] {puts $books($in)}
  C) foreach in [array names T* books] {puts $books($in)}

10) Which command will display the string "Tom Sawyer"
array set books {
    Twain "Tom Sawyer"
    Twain "Huck Finn"
    Welch "Practical Programming in Tcl/Tk"
    Flynt "Tcl/Tk: A Developer's Guide"}
  A) puts $books(Twain)
  B) puts [lindex $books(Twain) 1]
  C) "Tom Sawyer" cannot be displayed.

1) Use a "foreach" loop to iterate through an array
  A) if all the processing will be done within that loop.
  B) if your code processes the array in multiple procedures.
  C) if the array indices are monotonically increasing integers.

2) Use the startsearch/nextelement/endsearch technique to iterate through an array if
  A) the indices are random strings.
  B) an array has more than 10,000 indices.
  C) you need to have multiple iterations through the array happening at once.

3) How will the indices of an "array names" or "array nextelement" iteration be ordered?
  A) Alphabetically.
  B) In the order they appear in the internal Tcl data structure.
  C) Numerically.

4) Can you control the order in which indices are returned using startsearch/nextelement?
  A) Yes
  B) No

5) Can you control the order in which indices are processed using "array names" and a "foreach" loop?
  A) Sort of, by using lsort on the list returned by "array names".
  B) Yes, by supplying multiple patterns to "array names"
  C) No
:TEXT_EN
D:

1) Tcl can open files
  A) To read only access.
  B) To write only access.
  C) For read only, write only, or read write access.

2) Tcl views files as
  A) blocks of data.
  B) streams of data that can be accessed from an arbitrary location.
  C) streams of data that must be accessed from byte 0 to the end.

3) Once a file is opened in read mode, your script can
  A) read data using the 'read' or 'gets' command.
  B) read data byte-by-byte using the 'gets' command.
  C) only write new data to the end of the file

4) To make your script read a single line from a stream you should

  A) use the read command.
  B) use the puts command.
  C) use the gets command.

5) Data can be sent to a stream with the
  A) puts command.
  B) puts or write commands.
  C) write command.

6) By default, all Tcl I/O is
  A) unbuffered.
  B) buffered.
  C) flushed.

7) What will be the contents of the file "example.txt" after this script is evaluated:
set of [open "example.txt" w]
puts $of "testing"
  A) nothing, because the stream has not been closed.
  B) nothing, because the stream has not been flushed.
  C) nothing, the stream must be flushed or closed to force the write.

8) You can use the "seek" command to
  A) implement block oriented data files.
  B) search for patterns in a file.
  C) measure the seek time of your file system.

1) The "file" and "glob" commands
  A) mimic the behavior of the Unix "file" and "glob" commands.
  B) provide platform independent ways to access a file system.
  C) can only be used under MS Windows.

2) To extract the name of a file from a full file path
  A) use the "file tail" command.
  B) use the "file dirname" command.
  C) use the "file rootname" command.

3) Which code will change the name of "/tmp/foo.text" to "/tmp/foo.txt"
  A) file rename "/tmp/foo.text" [file dirname "/tmp/foo.text"].txt
  B) file rename "/tmp/foo.text" [file base "/tmp/foo.text"].txt
  C) file rename "/tmp/foo.text" [file rootname "/tmp/foo.text"].txt

4) The "file size" command will
  A) Return the number of disk blocks a file consumes.
  B) Return the size of a file in bytes.
  C) Return the size of the file system.

5) What will be the contents of "path" after this line of code is evaluated.
set path [file split "C:/Program Files/Tcl/bin/tclsh"]
  A) C: Program Files Tcl bin tclsh
  B) C: {Program Files} Tcl bin tclsh
  C) C:/Program Files/Tcl/bin/tclsh

6) What will the contents of "folder" be after this script is evaluated:
set folder [file normalize "/tmp/../etc/passwd"]
  A) /etc/passwd
  B) /tmp/etc/passwd
  C) ../etc/passwd

7) The "file mkdir" command will:
  A) Create a new file in a private folder.
  B) Create a temporary folder.
  C) Create a new empty folder.

8) The command "glob X:/DoesNotExist/*.ext" will probably:
  A) return an empty string.
  B) throw a Tcl error.
  C) return the string "No disk X:"

9) The "file tail" command will
  A) return only the name of a file without the rest of the path.
  B) return the file's extension.
  C) return the part of a filename that comes after the last underscore.

10) The "file mtime" and "file atime" commands return
  A) The time as a human readable string.
  B) The number of seconds since Jan 1, 1980.
  C) The number of seconds since Jan 1, 1970.

1) The "exec" command will
  A) execute an operating system level command and return the results.
  B) execute a set of Tcl commands.
  C) invoke the operating systems "executive" layer.

2) The "open" command can
  A) create a new folder.
  B) open a stream connection to a running program.
  C) start a program and open a stream connection to it.

3) The exec command will return results
  A) as they become available.
  B) after the executed program exits.
  C) when the I/O buffer is filled.

4) The "exec" command can
  A) only run a single program.
  B) run multiple programs in a pipeline.
  C) run multiple programs in parallel, each using a separate channel.

5) The "open" command can
  A) run a single program.
  B) run multiple programs in a pipeline.
  C) run multiple programs in parallel, each using a separate channel.
  D) all of the above.

6) If a program being run with the "exec" command generates an exception return
  A) the "exec" command will throw an error.
  B) the Tcl script ignores the return.
  C) a Tk alert is displayed on the screen.

7) The "exec" command will block a Tcl script until the system command is complete unless:
  A) the "exec" argument list includes the "-noblock" flag.
  B) the "exec" argument list ends with "&".
  C) the "exec" argument list starts with "&".

1) The "info commands" command
  A) returns a list of commands the user has defined.
  B) returns a list of all known commands.
  C) returns a list of command defined in the base Tcl interpreter.

2) The "info procs" command returns
  A) a list of commands the user has defined.
  B) a list of commands defined with the "proc" command only.
  C) a list of commands defined in packages.

3) The "info globals" command will return
  A) a list of all defined globals.
  B) a list of all global variables visible from the current scope.
  C) a list of all global variables that have been modified by this script.

4) If you evaluate "info locals" in the global scope it will:
  A) return a list of all global variables.
  B) return an empty string.
  C) generate an error.

5) If a command is displayed with "info commands" but not "info procs" it means
  A) the command was deleted by info commands.
  B) the command is implemented in compiled "C" code.
  C) the command cannot be replaced by a user procedure.

1) The "info patchlevel" and "info tclversion" commands can be used
  A) the number of patches that have been applied to this version of Tcl.
  B) to determine the revision level of a script.
  C) to determine the version of Tcl interpreter evaluating a script.

2) When this script is evaluated it will display:
puts "[file normalize [info script]]"
  A) the full path to the script being evaluated.
  B) the name of the file being evaluated.
  C) the name of the procedure that contains this line.

3) When this procedure is evaluated it will
proc tst {a} {puts [info level [info level]]}
  A) display the name of the procedure.
  B) display "tst a"
  C) display the name of the procedure (tst) and value of the argument.

1) What will be displayed when this script is evaluated:
proc tst {a} {puts "a"}
puts "[info args tst]"
  A) "a"
  B) "args for tst are 'a'"
  C) "tst {a}"

2) The "info body" command:
  A) returns the "C" code that implements a compiled command.
  B) returns the body of a Tcl procedure.
  C) returns the first N lines of a Tcl procedure.

3) To determine if the arguments to a procedure have default values,
  A) use the "info default" command.
  B) use the "info args -default" command.
  C) use the "info procedure -all" command.

4) What will this procedure do:
proc unique {{val 0}} {
  incr val
  proc unique "{val $val}" [info body unique]
  return $val
}
  A) Always return 0
  B) Rewrite itself each time it's evaluated with a new default value.
  C) return the string "$val"

1) The "source" command
  A) will read a file from a network repository of files.
  B) loads and evaluates a Tcl script file.
  C) evaluates one script within another.

2) A file to be sourced:
  A) May contain only one procedure.
  B) May contain multiple procedures and global scope scripts.
  C) May not assign values to global variables.

3) A file being sourced
  A) must be in simple ASCII.
  B) must be in OpenDoc format.
  C) must be a PDF file.

4) If Tcl encounters an error while "source"-ing a file
  A) it resets and starts over.
  B) it continues and returns the number of errors seen.
  C) it aborts immediately and displays an error.

5) You should split code into multiple source files
  A) with one procedure per source file.
  B) with one set of related functionality per source file.
  C) whenever you have more than 23 lines in a procedure.


1) A package can
  A) include only one procedure.
  B) include only Tcl scripts.
  C) include multiple compiled and Tcl script files.

2) Packages are created
  A) with the "pkg_mkIndex" command.
  B) by including the "package provide" command.
  C) by including the "package provide" command and creating a "pkgIndex.tcl" file.

3) A package can be loaded
  A) with the "source" command.
  B) with the "package require" command.
  C) with the "package provide" command.

4) You should use the "source" command instead of "package require"
  A) if the file is unique to this application and will always be in a known location.
  B) under no circumstances.
  C) if you only want one procedure from a package.

5) An application can load a package
  A) with the "unknown" command.
  B) with the "package require" command.
  C) with the "source" command.

6) Packages are
  A) only provided by the Tcl core developers.
  B) always written in "C".
  C) created whenever an application needs a library of related functions.

7) The "pkg_mkIndex" command
  A) will create an index file used by "package require".
  B) copy a set of related files into a package library.
  C) compress a set of Tcl scripts.

1) If you need to convert a list into separate arguments for a procedure
  A) use the {*} operator.
  B) use the {*} operator unless this is a legacy application running on Tcl8.4 or earlier.
  C) use the "split" command.

2) The "eval" command is
  A) useful when writing dynamic code that constructs new commands.
  B) no longer of value.
  C) only used by Domain Specific Language writers.

3) This script will
set i 2
set cmd "i 1"
incr $cmd
  A) syntax error.
  B) change the value of i to 3.
  C) set the value of i to "i 1"

4) What will be the value of lst1 after this script is evaluated:
set lst1 {a b c}
set lst2 {d e f}
lappend lst1 {*}$lst2
  A) a b c {d e f}
  B) a b c d e f
  C) {a b c} {d e f}

5) What will be the value of lst1 after this script is evaluated:
set lst1 {a b c}
set lst2 {d e f}
lappend lst1 $lst2
  A) a b c {d e f}
  B) a b c d e f
  C) {a b c} {d e f}

1) Which command will not generate an error:
  A) puts "two words"
  B) eval puts "two words"
  C) puts two words

2) What will this script print:
set args -nonewline
set args -nonewline
lappend args "this is a test"
puts $args
  A) -nonewline {this is a test}.
  B) "this is a test", with no newline at the end.
  C) nothing - generates an error.

3) The "info complete" command will
  A) return true when a procedure has completed running.
  B) return true when a Tcl command is complete.
  C) returns true when an application has completed execution.

4) The eval command
  A) drops one level of grouping the arguments.
  B) evaluates a Bourne .sh or DOS .bat file.
  C) evaluates an arithmetic expression.


1) The "subst" command
  A) will substitute one variable with another.
  B) will perform repeated substitution passes until all $varNames are replaced.
  C) will perform a substitution pass, replacing $varName with the contents of a variable

2) The "subst" command
  A) can be used to implement indirection.
  B) can be used with puts, but no other commands.
  C) is not used at all.

3) You can use the "subst" command
  A) to replace a variable with it's contents.
  B) to perform multiple passes of substitution before evaluating a command.
  C) to substitute languages.

4) What will this script print
 array set french {I Je speak parlez French Francais}
 set language french
 foreach word {I speak French} {
  if {[info exists ${language}($word)]} {
    puts -nonewline "[subst $${language}($word)] "
  } else {
    puts -nonewline "$word "
  }
}
  A) No output - generates an error.
  B) I speak French
  C) Je parlez Francais

1) A Tcl script executes in the folder
  A) where the file tclsh exists.
  B) where the main script exists.
  C) from which tclsh is invoked.

2) The "pwd" command reports
  A) the current working directory for the script.
  B) the directory where the script was started.
  C) the directory where the libraries reside.

3) The "cd" command
  A) move a script to a new location.
  B) will change the current working directory for a script.
  C) modify the file system.

4) The command "open log.txt w" will
  A) open a file in the log folder.
  B) open a file in the current working directory.
  C) open a file in the folder with the script.


1) The "return" command
  A) only returns a value.
  B) can only be used once in a procedure.
  C) can return a value and one of several status conditions.

2) The "catch" command
  A) will catch errors and return them to the operating system layer.
  B) will catch an error in a script and return a "true" if an error occurred.
  C) can only be used when evaluating procedures.

3) The "error" command
  A) sets an error state which will be returned when the procedure is complete.
  B) generates an error and aborts processing the script.
  C) tests a script to see if it will generate an error when it's run.

4) What will this script print:
puts [catch {expr {2+a}}]
  A) 0
  B) 1
  C) invalid bareword "a"

5) What will be the contents of x after this script is evaluated:
catch {expr {2+1}} x
  A) 1
  B) 0
  C) 3

6) What will this script display:
set input x
if {[catch expr {$input+2} result]} {
  error "Bad value for input"
} else {
  puts "Result: $result"
}

  A) Result: x+2
  B) Bad value for input
  C) syntax error

7) What is a likely contents for $errorInfo after evaluating this script?
set input x
if {[catch expr {$input+2} result]} {
  error "Bad value for input"
} else {
  puts "Result: $result"
}

  A) wrong # args: should be "expr arg ?arg ...?"
  B) invalid bareword "x"
  C) errorInfo will be an empty string.

1) The "trace variable" command can
  A) generate an exception when a variable is written to a log file.
  B) generate an exception if a read-only variable is modified.
  C) evaluate a script when a variable is read.

2) The "trace info variable"
  A) will return the names of variables with traces.
  B) must be called with the name of variable.
  C) will return information about all variables with traces.

3) The "trace delete variable" command
  A) must be called from within the procedure referenced by a "trace add variable".
  B) only deletes traces that have been activated at least once.
  C) will remove one trace from a single variable.

4) What will this script print:
proc traceProc {n i o} {puts "Name: $n Index: $i Operation: $o"}
trace add variable x write traceProc
proc mm {an} {upvar $an z; set z 2}
mm x
  A) Name: x Index:  Operation: write
  B) Name: z Index:  Operation: write
  C) nothing - generates an error.

5) What output will this script generate:
trace add variable qq array traceProc
proc traceProc {n i o} {puts "Name: $n Index: $i Operation: $o"}
set qq(x) y
 A) Name: qq Index:  Operation: array
 B) Name: qq Index: x Operation: array
 C) none - set is not an "array" operation.

1) A script can access the command line variables it was invoked with
  A) using the "argv0" array.
  B) using the "argc" array.
  C) using the "argv" array.

2) The "env" global array
  A) contains all the environment variables set by the operating system.
  B) contains only the environment variables used internally by Tcl.
  C) contains only env indices set within your script.

3) What will this script display:
proc showEnv {} {
  parray env
}
showEnv

  A) Nothing
  B) The contents of the env() array.
  C) The Tcl specific parts of the env() array.

4) The "env" array
  A) is only available when tclsh is running on a Unix system.
  B) is available only on Windows systems.
  C) contains whatever environment variables are defined on any system.

1) The "time" command
  A) returns the time of day in seconds since 1970.
  B) returns the length of time it takes a script to be evaluated in milliseconds.
  C) returns the length of time since the "time start" command was evaluated.

2) You should use the "unset" command
  A) to destroy all variables before a Tcl script exits.
  B) to be certain no variables are left over from a previous invocation of tclsh.
  C) if your script creates variables so large that you may exhaust the system memory.

3) If your script tries to "unset" a variable that has not been defined
  A) "unset" will generate an error.
  B) "unset" will delete the variable if it ever is defined.
  C) "unset" will return the current value of the variable.

4) The "unset" command
  A) should be used for all procedure local variables before the procedure returns.
  B) should be used for all global variables before an application exits.
  C) is not needed for most scripts.


1) The "socket" command
  A) can create both client and server sockets.
  B) only creates client side sockets.
  C) creates sockets that can only read.

2) The "fileevent" command
  A) generates an event on an I/O channel.
  B) allows a script to modify the behavior of a channel.
  C) registers a script to be evaluated when a channel has data to be read.

3) The "vwait" command
  A) waits for a period of time.
  B) returns control to the event loop until a variable is modified.
  C) waits for a variable to be destroyed.

4) What 3 arguments are added when a script registered with the "socket -server" command
is evaluated as a result of a socket being opened.

  A) Channel, IP Address, and Port Number.
  B) Channel, IP Address, and Permissions.
  C) Read Procedure, Write Procedure and Permissions

5) After a socket is created
  A) data can be read with sockread and sent with sockwrite.
  B) data can be read with gets and sent with puts.
  C) it must be configured for read or write access.


1) The "clock seconds" command
  A) returns the number of seconds since 1980
  B) returns the number of seconds since 1970
  C) returns the number of seconds since a operating system-defined date.

2) The "clock scan" command
  A) will try to convert a human readable date/time to seconds.
  B) will scan a timestamp and split it into year, month, day, hour, minute and seconds.
  C) only works for US formatted timestamps.

3) The "clock format" command
  A) will convert US format dates to European format.
  B) will convert a time in seconds to a human readable format.
  C) will convert time in 24 hour clock to 12 hour time with AM/PM.


1) The "fconfigure" command will
  A) generate an event when a channel's configuration is modified.
  B) allow a script to modify the behavior of a channel.
  C) is only supported on Windows.

2) The "fblocked" command will
  A) block input on a channel - useful for spam prevention.
  B) return 1 if there is data available on a channel.
  C) return 1 if a channel has been blacklisted.

3) The "fconfigure" command can
  A) be used to write files with the "operating system normal" line endings.
  B) configure a channel to connect to a file, terminal or socket.
  C) configure a channel to be read-only.

4) Non-Blocked I/O is useful
  A) when an application is using a round-robin approach to load leveling.
  B) for files with very long lines.
  C) for channels that contain binary data.

1) A new "interp"
  A) can be started on a separate computer on the local network.
  B) shares global variables with the primary interpreter.
  C) has it's own global variables and procedures.

2) When an application creates 2 interps and one interp executes an infinite loop
  A) the other interp continues to run.
  B) the other interp is blocked from execution.
  C) the other interp takes control.

3) You can create procedures in a new interpreter
  A) with the "interp create" command.
  B) with the "interp eval" command.
  C) with the "interp proc" command

4) If you create a new interpreter with "interp create -safe"
  A) it will be unable to access the filesystem.
  B) it will not be able to create procedures.
  C) all procedures created in that interpreter will be tested for buffer overruns.

5) You can link selected "unsafe" procedures into a "safe" interpreter
  A) with "interp configure".
  B) with "interp eval".
  C) with "interp alias".

1) A dict
  A) links a key and value but will not retain the order.
  B) links a key and value and retains the order of the elements.
  C) is an ordered list of values.

2) The "dict size" command
  A) returns the size of the largest value in a dict.
  B) returns the number of keys and values in a dict.
  C) returns the number of key/value pairs in a dict.

3) A dict structure
  A) can be nested arbitrarily deep.
  B) contains only one level of key/value pairs.
  C) must be indexed with an integer.

4) To retrieve the value associated with $key from a dict
  A) use "dict get" with $key
  B) use "dict array($key)"
  C) use dict $key

5) To show all the keys in a dict
  A) use the "dict show keys" command.
  B) use the "dict keys" command.
  C) use the "dict configure -keys" command.


1) A dict can include duplicated keys
  A) True
  B) False


2) How many key/value pairs will this script create in dict1?
dict set dict1 a b c d
  A) 2
  B) 1
  C) 4

3) You can iterate through all the contents in a dict with
  A) the "dict for" command
  B) the "dict foreach" command
  C) the "dict loop" command

4) The "dict with" command
  A) will accept a dictionary and create variable named for each key and assign the appropriate value.
  B) will accept a dictionary and an arrayname and create an array in which each key is an index.
  C) will accept a dictionary and return the values with keys that match a glob value.


1) Which is the resulting dict after this command is evaluated?
dict set dict1 a b c d
  A) a b c d
  B) a {b c d}
  C) a {b {c d}}

2) Dictionaries can be nested
  A) two layers deep.
  B) arbitrarily deeply.
  C) to one level of indirection.

3) A dictionary can be used
  A) in place of a Tcl list.
  B) instead of the "string" commands.
  C) to implement complex data structures.

1) When "dict set" is evaluated with a key that is already in the dict
  A) the previous values associated with that key are replaced with new values.
  B) a new copy of that key, with new values is created.
  C) a new, unique key is fabricated by adding "1" to the key.

2) The "dict replace" command will
  A) replace keys and values with new keys and values.
  B) return a new dict with a new value associated with an existing key.
  C) replace a value with a new value and modify the dict.

3) If a key does not exist, "dict replace" will
  A) add that key/value pair to the end of the dictionary.
  B) add that key/value pair to the beginning of the dictionary.
  C) not insert the new key/value pair.

4) The "dict update" command
  A) can modify a key in a dict.
  B) can modify a value in a dict.
  C) can modify both keys and values in a dict.

5) What will be the final values for dict1 after this script is evaluated.
dict set dict1 a b
dict update dict1 a x {set x c}
  A) a c
  B) a b
  C) a x

Exercises:
;# This is a single line comment
puts "Hello, World - In quotes"    ;# This is a comment after the command.
puts {Hello, World - In Braces}          # Add a semicolon to make this OK

;# Because of the semicolon this is two puts commands on one line.
puts "This is line 1"; puts "this is line 2"

;# The semicolon inside quotes does not end the command
puts "Hello, World; - With  a semicolon inside the quotes"
-------------------------
;# Assign a string to variable X
set X "This is a string"

;# Assign a number to variable Y
set Y 1.24

;# Display the contents  of X and Y
puts $X
puts $Y

;# Just puts a divider
puts "..............................."

;# More than one item can be put in a single puts
set label "The value in Y is: "
puts "$label $Y"

Result:
This is a string
1.24
...............................
The value in Y is:  1.24
----------------------------------------
;# Show how a \ affects the $
set Z "Albany"
set Z_LABEL "The Capitol of New York is: "

puts "$Z_LABEL $Z"
puts "$Z_LABEL \$Z"

;# The next line needs a backslash to escape the '$'
puts "\nBen Franklin is on the $100.00 bill"

set a 100.00
puts "Washington is not on the $a bill"    ;# This is not what you want
puts "Lincoln is not on the $$a bill"      ;# This is OK
puts "Hamilton is not on the \$a bill"     ;# This is not what you want
puts "Ben Franklin is on the \$$a bill"    ;# But, this is OK

puts "\n................. examples of escape strings"
puts "Tab\tTab\tTab"
puts "This string prints out \non two lines"
puts "This string comes out\
on a single line"

result:
The Capitol of New York is:  Albany
The Capitol of New York is:  $Z

--------
can't read "100": no such variable
    while executing
"puts "\nBen Franklin is on the $100.00 bill""

------------------------------------------------
set Z "Albany"
set Z_LABEL "The Capitol of New York is: "

puts "\n................. examples of differences between  \" and \{"
puts "$Z_LABEL $Z"
puts {$Z_LABEL $Z}

puts "\n....... examples of differences in nesting \{ and \" "
puts "$Z_LABEL {$Z}"
puts {Who said, "What this country needs is a good $0.05 cigar!"?}

puts "\n................. examples of escape strings"
puts {There are no substitutions done within braces \n \r \x0a \f \v}
puts {But, the escaped newline at the end of a\
string is still evaluated as a space}
output:
................. examples of differences between  " and {
The Capitol of New York is:  Albany
$Z_LABEL $Z

....... examples of differences in nesting { and "
The Capitol of New York is:  {Albany}
Who said, "What this country needs is a good $0.05 cigar!"?

................. examples of escape strings
There are no substitutions done within braces \n \r \x0a \f \v
But, the escaped newline at the end of a string is still evaluated as a space

-----------------------------------------------
set x "abc"
puts "A simple substitution: $x\n"

set y [set x "def"]
puts "Remember that set returns the new value of the variable: X: $x Y: $y\n"

set z {[set x "This is a string within quotes within braces"]}
puts "Note the curly braces: $z\n"

set a "[set x {This is a string within braces within quotes}]"
puts "See how the set is executed: $a"
puts "\$x is: $x\n"

set b "\[set y {This is a string within braces within quotes}]"
puts "Note the \\ escapes the bracket:\n \$b is: $b"
puts "\$y is: $y"

output:
A simple substitution: abc

Remember that set returns the new value of the variable: X: def Y: def

Note the curly braces: [set x "This is a string within quotes within braces"]

See how the set is executed: This is a string within braces within quotes
$x is: This is a string within braces within quotes

Note the \ escapes the bracket:
 $b is: [set y {This is a string within braces within quotes}]
$y is: def

set X 100;
set Y 256;
set Z [expr "$Y + $X"]
set Z_LABEL "$Y plus $X is "

puts "$Z_LABEL $Z"
puts "The square root of $Y is [expr sqrt($Y)]\n"

puts "Because of the precedence rules \"5 + -3 * 4\"   is: [expr -3 * 4 + 5]"
puts "Because of the parentheses      \"(5 + -3) * 4\" is: [expr (5 + -3) * 4]"

puts "\n................. more examples of differences between  \" and \{"
puts {$Z_LABEL [expr $Y + $X]}
puts "$Z_LABEL {[expr $Y + $X]}"
puts "The command to add two numbers is: \[expr \$a + \$b]"
Output:
256 plus 100 is  356
The square root of 256 is 16.0

Because of the precedence rules "5 + -3 * 4"   is: -7
Because of the parentheses      "(5 + -3) * 4" is: 8

................. more examples of differences between  " and {
$Z_LABEL [expr $Y + $X]
256 plus 100 is  {356}
The command to add two numbers is: [expr $a + $b]

--------------------------------------------------------------------------------
;# Set the variables we'll be comparing
set x "ONE";
set y 1;
set z "ONE";

;# This is legal
switch $x "ONE" "puts ONE=1" "TWO" "puts TWO=2" "default" "puts NO_MATCH"

;# This is more readable, the patterns are to the left, and the body
;#             associated with each pattern is to its right.
switch $x \
  "ONE"                 "puts ONE=1"  \
  "TWO"                "puts TWO=2" \
  "default"             "puts NO_MATCH";

;# These two examples show the difference between using the un-braced and
;#   braced versions of the switch command.
;# You can also see how a switch command can become too complex to
;#   be written on a single line.

;# This form allows substitution in the pattern arguments.

switch $x \
  "$z"                      {set y1 [expr $y+1]; puts "MATCH \$z. $y + $z is $y1" } \
  "ONE"                 {set y1 [expr $y+1]; puts "MATCH ONE. $y + one is $y1"} \
  "TWO"                                {set y1 [expr $y+2]; puts "MATCH TWO. $y + two is $y1" } \
  "THREE"            {set y1 [expr $y+3]; puts "MATCH THREE. $y + three is $y1" } \
  "default"             {puts "$x does not match any of these choices";}

;# This form of the command disables variable substitution in the pattern

switch $x {
  "$z"                      {set y1 [expr $y+1]; puts "MATCH \$z. $y + $z is $y1" }
  "ONE"                 {set y1 [expr $y+1]; puts "MATCH ONE. $y + one is $y1"}
  "TWO"                                {set y1 [expr $y+2]; puts "MATCH TWO. $y + two is $y1"}
  "THREE"            {set y1 [expr $y+3]; puts "MATCH THREE. $y + three is $y1"}
  "default"             {puts "$x is NOT A MATCH"}
  }

Output:
ONE=1
ONE=1
MATCH $z. 1 + ONE is 2
MATCH ONE. 1 + one is 2
------------------------------------------------------------------------------
set x 1;

if {$x == 2} {puts "$x is 2"} else {puts "$x is not 2"}

if {$x != 1} {
  puts "$x is != 1"
  } else {
  puts "$x is 1"
  }

if $x==1 {puts "GOT 1"}

;# Two passes of substitution will be done on this test string
;#  The initial pass replaces $y with x
;#  Within the if statement, $x is replaced with 1

set y x;
if "$$y != 1" {
  puts "$$y is != 1"
  } else {
  puts "$$y is 1"
  }
Output:
1 is not 2
1 is 1
GOT 1
$x is 1
set x 1;

# This is a normal way to write a Tcl
# while loop.

while {$x < 5} {
    puts "x is $x";
    set x [expr $x + 1]
    }

puts "exited first loop with X equal to $x\n"

# The next example shows the difference between ".." and {...}
# How many times does the following loop run?
# Why does it not print on each pass?

set x 0;
while "$x < 5" {
                set x [expr $x + 1]
                if {$x > 7} break;
                if "$x > 3" continue;
                puts "x is $x";
                }

puts "exited second loop with X equal to $x"

output:
x is 1
x is 2
x is 3
x is 4
exited first loop with X equal to 5

x is 1
x is 2
x is 3
exited second loop with X equal to 8

for {puts "Start"; set i 0} {$i < 2} {incr i; puts "I after incr: $i"; } {
  puts "I inside first loop: $i"
  }

;# Because the test is evaluated before the body,
;#  this loop won't execute the body of the code.

for {puts "Start"; set i 3} {$i < 2} {incr i; puts "I after incr: $i"; } {
  puts "I inside second loop: $i"
  }

;# A while loop equivalent to the first for loop:

puts "Start"; set i 0;
while {$i < 2} {
  puts "I inside first loop: $i"
  incr i;
  puts "I after incr: $i";
  }

Output:
Start
I inside first loop: 0
I after incr: 1
I inside first loop: 1
I after incr: 2
Start
Start
I inside first loop: 0
I after incr: 1
I inside first loop: 1
I after incr: 2


proc sum {arg1 arg2} {
  set x [expr $arg1+$arg2];
  return $x
  }

puts " The sum of 2 + 3 is: [sum 2 3]\n\n"

proc for {a b c} {
                puts "The for command has been replaced by a puts";
                puts "The arguments were: $a\n$b\n$c\n"
                }

for {set i 1} {$i < 10} {incr i}
output:
The sum of 2 + 3 is: 5


The for command has been replaced by a puts
The arguments were: set i 1
$i < 10
incr i

proc example {first {second ""} args} {
  if {$second == ""} {
    puts "There is only one argument and it is: $first";
    return 1;
    } else {
    if {$args == ""} {
      puts "There are two arguments - $first and $second";
      return 2;
      } else {
      puts "There are many arguments - $first and $second and $args";
      return "many";
      }
    }
  }

set count1 [example ONE]
set count2 [example ONE TWO]
set count3 [example ONE TWO THREE ]
set count4 [example ONE TWO THREE FOUR]
output:
There is only one argument and it is: ONE
There are two arguments - ONE and TWO
There are many arguments - ONE and TWO and THREE
There are many arguments - ONE and TWO and THREE FOUR
The example was called with 1, 2, many, and many Arguments

;# An example of Upvar
;# Convert a value to a positive number before assigning.
proc SetPositive {variable value } {
  upvar $variable myvar;
  if {$value < 0} { set myvar [expr -$value];} else {set myvar $value;}
  return $myvar;
  }

SetPositive x 5;
SetPositive y -5;

puts "X : $x    Y: $y\n"
;# nesting Upvars

;# A second level proc - This will be called by one
proc two {y} {
  upvar 1 $y z                                      ;# tie the calling value to variable z
  upvar 2 x a                                        ;# Tie variable x two levels up  to a
  puts "two: Z: $z A: $a"   ;# Output the values, just to confirm
  set z 1;                                 ;# Set z, the passed variable to 1;
  set a 2;                                 ;# Set x, two layers up to 2;
  }

;# A first level proc - This will be called by the global space code.
proc one {y} {
  upvar $y z                                         ;# This ties the calling value to variable z
  puts "one: Z: $z"                              ;# Output that value, to check it is 5
  two z;                                  ;# call proc two, which will change the value
  }

one y;                                                     ;# Call one, and output X and Y after the call.
puts "\nX: $x  Y: $y"
output:
X : 5    Y: 5

one: Z: 5
two: Z: 5 A: 5

X: 2  Y: 1

set x "a b c"
puts "Item 2 of the list {$x} is: [lindex $x 2]\n"

set y [split 7/4/1776 "/"]
puts "We celebrate on the [lindex $y 1]'th day of the [lindex $y 0]'th month\n"

set z [list puts "arg 2 is $y" ]
puts "A command resembles: $z\n"

set i 0;
foreach j $x {
  puts "$j is item number $i in list x"
  incr i;
  }
Output:
Item 2 of the list {a b c} is: c

We celebrate on the 4'th day of the 7'th month

A command resembles: puts {arg 2 is 7 4 1776}

a is item number 0 in list x
b is item number 1 in list x
c is item number 2 in list x

set b [list a b {c d e} {f {g h}}]
puts "Treated as a list: $b\n"

set b [split "a b {c d e} {f {g h}}"]
puts "Transformed by split: $b\n"

set a [concat a b {c d e} {f {g h}}]
puts "Concated: $a\n"

lappend a {ij K lm}                                            ;# Note: {ij K lm} is a single element
puts "After lappending: $a\n"

set b [linsert $a 3 "1 2 3"]                 ;# "1 2 3" is a single element
puts "After linsert at position 3: $b\n"

;# "AA" and "BB" are two list elements.
set b [lreplace $b 3 5 "AA" "BB"] 
puts "After lreplacing 3 positions with 2 values at position 3: $b\n"
output:
Treated as a list: a b {c d e} {f {g h}}

Transformed by split: a b \{c d e\} \{f \{g h\}\}

Concated: a b c d e f {g h}

After lappending: a b c d e f {g h} {ij K lm}

After linsert at position 3: a b c {1 2 3} d e f {g h} {ij K lm}

After lreplacing 3 positions with 2 values at position 3: a b c AA BB f {g h} {ij K lm}

set list [list {Washington 1789} {Adams 1797} {Jefferson 1801} \
               {Madison 1809} {Monroe 1817} {Adams 1825} ]

set x [lsearch $list Washington*];
set y [lsearch $list Madison*];
incr x; incr y -1;                  ;# Set range to be not-inclusive

set subsetlist [lrange $list $x $y]

puts "The following presidents served between Washington and Madison"
foreach item $subsetlist {
  puts "Starting in [lindex $item 1]: President [lindex $item 0] "
  }

set x [lsearch $list Madison*]

set srtlist [lsort $list];
puts $srtlist
set y [lsearch $srtlist Madison*];

puts "\n$x Presidents came before Madison chronologically"
puts "$y Presidents came before Madison alphabetically"

output:
The following presidents served between Washington and Madison
Starting in 1797: President Adams
Starting in 1801: President Jefferson
{Adams 1797} {Adams 1825} {Jefferson 1801} {Madison 1809} {Monroe 1817} {Washington 1789}

3 Presidents came before Madison chronologically
3 Presidents came before Madison alphabetically

set string "this is my test string"

puts "There are [string length $string] characters in \"$string\""

puts "[string index $string 1] is the second character in \"$string\""

puts "\"[string range $string 5 10]\" are characters between the 5'th and 10'th"

output:

There are 22 characters in "this is my test string"
h is the second character in "this is my test string"
"is my " are characters between the 5'th and 10'th

set fullpath "/usr/home/clif/TCL_STUFF/TclTutor/Lsn.17"
set relativepath "CVS/Entries"
set directorypath "/usr/bin/"

set paths [list $fullpath $relativepath $directorypath]

foreach path $paths  {
  set first [string first "/" $path];
puts $first
  set last [string last "/" $path];
puts $last
  ;# Report whether path is absolute or relative

  if {$first != 0} {
    puts "$path is a relative path"
    } else {
    puts "$path is an absolute path"
    }

  ;# If "/" is not the last character in $path, report the last word.
  ;# else, remove the last "/", and find the next to last "/", and
  ;#   report the last word.

  incr last;
  if {$last != [string length $path]} {
    set name [string range $path $last end];
    puts "The file referenced in $path is $name"
    } else {
    incr last -2;
    set tmp [string range $path 0 $last];
    set last [string last "/" $tmp];
    incr last;
    set name [string range $tmp $last end]
    puts "The final directory in $path is $name"
    }

  ;# CVS is a directory created by the CVS source code control system.
  ;#

  if {[string match "*CVS*" $path]} {
    puts "$path is part of the source code control tree"
    }

  ;# Compare to "a" to determine whether the first char is upper or lower case
  set comparison [string  compare $name "a"]
  if {$comparison >= 0} {
    puts "$name starts with a lowercase letter\n"
    } else {
    puts "$name starts with an uppercase letter\n"
    }
  }

Output:
0
33
/usr/home/clif/TCL_STUFF/TclTutor/Lsn.17 is an absolute path
The file referenced in /usr/home/clif/TCL_STUFF/TclTutor/Lsn.17 is Lsn.17
Lsn.17 starts with an uppercase letter

3
3
CVS/Entries is a relative path
The file referenced in CVS/Entries is Entries
CVS/Entries is part of the source code control tree
Entries starts with an uppercase letter

0
8
/usr/bin/ is an absolute path
The final directory in /usr/bin/ is bin
bin starts with a lowercase letter

set upper "THIS IS A STRING IN UPPER CASE LETTERS"
set lower "this is a string in lower case letters"
set trailer "This string has trailing dots ...."
set leader "....This string has leading dots"
set both  "((this string is nested in parens )))"

puts "tolower converts this: $upper"
puts "              to this: [string tolower $upper]\n"
puts "toupper converts this: $lower"
puts "              to this: [string toupper $lower]\n"
puts "trimright converts this: $trailer"
puts "                to this: [string trimright $trailer .]\n"
puts "trimleft converts this: $leader"
puts "               to this: [string trimleft $leader .]\n"
puts "trim converts this: $both"
puts "           to this: [string trim $both "()"]\n"

set labels [format "%-20s %+10s " "Item" "Cost"]
set price1 [format "%-20s %10d Cents Each" "Tomatoes" "30"]
set price2 [format "%-20s %10d Cents Each" "Peppers" "20"]
set price3 [format "%-20s %10d Cents Each" "Onions" "10"]
set price4 [format "%-20s %10.2f per Lb." "Steak" "3.59997"]

puts "\n Example of format:\n"
puts "$labels"
puts "$price1"
puts "$price2"
puts "$price3"
puts "$price4"

output;
trim converts this: ((this string is nested in parens )))
           to this: this string is nested in parens


 Example of format:

Item                       Cost
Tomatoes                     30 Cents Each
Peppers                      20 Cents Each
Onions                       10 Cents Each
Steak                      3.60 per Lb.

set sample "Where there is a will, There is a way."

set result [regexp {[a-z]+} $sample match]
puts "Result: $result match: $match"

set result [regexp {([A-Za-z]+) +([a-z]+)} $sample match sub1 sub2 ]
puts "Result: $result Match: $match 1: $sub1 2: $sub2"

regsub "way" $sample "lawsuit" sample2
puts "New: $sample2"

Output:
Result: 1 match: here
Result: 1 Match: Where there 1: Where 2: there
New: Where there is a will, There is a lawsuit.

set list1 [list {/dev/wd0a        17086    10958     5272    68%    /}\
{/dev/wd0f       179824   127798    48428    73%    /news}\
{/dev/wd0h      1249244   967818   218962    82%    /usr}\
{/dev/wd0g        98190    32836    60444    35%    /var}]

foreach line $list1 {
  regexp {[^ ]* *([0-9]+)[^/]*(/[a-z]*)} $line match size mounted;
  puts "$mounted is $size blocks"
  }

set line {Interrupt Vector?               [32(0x20)]}
regexp "\[^\t]+\t\\\[\[0-9]+\\(0x(\[0-9a-fA-F]+)\\)]" $line match hexval
puts "Hex Default is: 0x$hexval"

set str2 "abc^def"
regexp "\[^a-f]*def" $str2 match
puts "using \[^a-f] the match is: $match"

regexp "\[a-f^]*def" $str2 match
puts "using \[a-f^] the match is: $match"

regsub {\^} $str2 " is followed by: " str3
puts "$str2 with the ^ substituted is: \"$str3\""

regsub "(\[a-f]+)\\^(\[a-f]+)" $str2 "\\2 follows \\1" str3
puts "$str2 is converted to \"$str3\""

Output:
/ is 17086 blocks
/news is 179824 blocks
/usr is 1249244 blocks
/var is 98190 blocks
Hex Default is: 0x20
using [^a-f] the match is: ^def
using [a-f^] the match is: abc^def
abc^def with the ^ substituted is: "abc is followed by: def"
abc^def is converted to "def follows abc"

array set array1 [list {123} {Abigail Aardvark} \
                                       {234} {Bob Baboon} \
                       {345} {Cathy Coyote} \
                                       {456} {Daniel Dog} ]

puts "Array1 has [array size array1] entries\n"

puts "Array1 has the following entries: \n [array names array1] \n"

puts "ID Number 123 belongs to $array1(123)\n"

if {[array exist array1]} {
   puts "array1 is an array"
   } else {
   puts "array1 is not an array"
   }

if {[array exist array2]} {
   puts "array2 is an array"
   } else {
   puts "array2 is not an array"
   }

Output:
Array1 has 4 entries

Array1 has the following entries:
 345 234 123 456

ID Number 123 belongs to Abigail Aardvark

array1 is an array
array2 is not an array

array set array1 [list {123} {Abigail Aardvark} \
                                       {234} {Bob Baboon} \
                       {345} {Cathy Coyote} \
                                       {456} {Daniel Dog} ]

;#
;# Simply iterating through an array with a foreach loop:
;#

foreach id [array names array1] {
  puts "$array1($id) has ID: $id"
  }

;#
;# Two procs iterating through the same array with iteration commands
;#

proc getrec_format1 {arrayVar searchid} {
  global $arrayVar
  upvar $searchid id
  set record [array nextelement $arrayVar $id];
  return "The current ID is: $record"
  }

proc getrec_format2 {arrayVar searchid} {
  global $arrayVar
  upvar $searchid id
  set record [array nextelement $arrayVar $id];
  return $record;
  }

set searchId [array startsearch array1];

puts ""
set item 0;
while {[array anymore array1 $searchId]} {
  incr item;
  if {[expr $item %2]} {
    set format1 [getrec_format1 array1 searchId]
    puts "item number: $item format 1: $format1"
    } else {
    set format2 [getrec_format2 array1 searchId]
    puts "item number: $item format 2: $format2"
    }
  }

Output:
Cathy Coyote has ID: 345
Bob Baboon has ID: 234
Abigail Aardvark has ID: 123
Daniel Dog has ID: 456

item number: 1 format 1: The current ID is: 345
item number: 2 format 2: 234
item number: 3 format 1: The current ID is: 123
item number: 4 format 2: 456

set fileid [open "/windows/temp/testfile" w+]

seek $fileid 0 start

puts $fileid "This is a test.\nIt is only a test"

seek $fileid 0 start

set chars [gets $fileid line1];
set line2 [gets $fileid];

puts "There are $chars characters in \"$line1\""
puts "The second line in the file is: \"$line2\""

seek $fileid 0 start

set buffer [read $fileid];
puts "\nTotal contents of the file are:\n$buffer"
close $fileid

output:

There are 15 characters in "This is a test."
The second line in the file is: "It is only a test"

Total contents of the file are:
This is a test.
It is only a test

;# Collect a bunch of files to compare

set ail1 [glob C:/windows/w*.dll]
set ail2 [glob C:/windows/win*.exe]

;# Set the format string (see Lsn.18), and display column headers

set fmt "%-12s %-16s %8s %-7s"
puts "[format "$fmt Comment" "Directory" "Name" "Inode" "Type"]"

;# Loop through the filenames collected by glob, and
;# determine their inode, size, and type.
;# Then display the results.

foreach name [concat $ail1 $ail2] { 
  ;# split the name into pieces for display:
  set dir [file dirname $name]
  set filename [file tail $name]
 
  ;# Collect some status and type info.
  file stat $name arr
  set type [file type $name]

  ;# Display what we've learned.
  puts -nonewline "[format $fmt $dir $filename $arr(ino) $type]"
 
  ;# and particular data depending on whether item is a file or symbolic link.

  if {[string match [file type $name] "link"]} {
      puts " points to: [file readlink $name]"
     }

  if {[string match [file type $name] "file"]} {
      puts " Size: [file size $name] bytes "
     }
  }

Output:
Directory    Name                Inode Type    Comment
C:/windows   wweb32.dll          28204 file    Size: 1192128 bytes
C:/windows   winhlp32.exe        50482 file    Size: 9728 bytes


# Create a unique (mostly) file name for a Tcl program
set tempFileName "C:/temp/inv_[pid].tcl"

# Open the output file, and
#   write a simple program to it

set outfl [open $tempFileName w]

puts $outfl {
    set len [gets stdin line]
    if {$len < 5} {exit -1}

    for {set i $len} {$i >= 0} {incr i -1} {
        append l2 [string range $line $i $i]
    }
    puts $l2
    exit 0;
}

# Flush and close the file
flush $outfl
close $outfl

# Run the new Tcl file interactively

# Open a pipe to the program
set io [open "|C:/Users/Nawraj/Desktop/tcltutor30b6.exe $tempFileName" r+]

# send a string to the new program
#     *MUST FLUSH*
puts $io "This will come back backwards."
flush $io

# Get the reply, and display it.
set len [gets $io line]

puts  "To reverse: 'This will come back backwards.'"
puts "Reversed is: $line"
puts "The line is $len characters long"

# Run the program with input defined in an exec call

set invert [exec C:/Users/Nawraj/Desktop/tcltutor30b6.exe $tempFileName << \
                "ABLE WAS I ERE I SAW ELBA"]

# display the results
puts "The inversion of 'ABLE WAS I ERE I SAW ELBA' is \n $invert"

# Clean up
file delete $tempFileName

Output:

--------
couldn't open "C:/temp/inv_4740.tcl": no such file or directory
    while executing
"open $tempFileName w"


;#
;# safeIncr checks for a variable's existence before
;# it tries to increment it.  If the variable does not exist,
;# it is initialized and returned.

proc safeIncr {val {amt 1}} {
  upvar $val v
  if {[info exists v]} { incr v $amt}  else { set v $amt }
  }

;#
;# Check that the safeIncr proc exists before invoking it.

if {[info procs safeIncr] == "safeIncr"} {
  safeIncr a
  }

puts "After calling SafeIncr with a non existent variable: $a"

set a 100
safeIncr a
puts "After calling SafeIncr with a variable with a value of 100: $a"

safeIncr b -3
puts "After calling safeIncr with a non existent variable by -3: $b"

set b 100
safeIncr b -3
puts "After calling safeIncr with a variable whose value is 100 by -3: $b"

puts "\nThese variables have been defined: [lsort [info vars]]"
puts "\nThese globals have been defined:   [lsort [info globals]]"

;#
;# Check for the existence of localproc
;#

set exist [info procs localproc];
if {$exist == ""} {
  puts "\nlocalproc does not exist at point 1"
  }

proc localproc {} {
  global argv;

  set loc1 1;
  set loc2 2;
  puts "\nLocal variables accessible in this proc are: [lsort [info locals]]"
  puts "\nVariables accessible from this proc are:     [lsort [info vars]]"
  puts "\nGlobal variables visible from this proc are: [lsort [info globals]]"
  }

set exist [info procs localproc];
if {$exist != ""} {
  puts "localproc does exist at point 2"
  }

localproc;

output:

After calling SafeIncr with a non existent variable: 1
After calling SafeIncr with a variable with a value of 100: 101
After calling safeIncr with a non existent variable by -3: -3
After calling safeIncr with a variable whose value is 100 by -3: 97

These variables have been defined: a argc argv argv0 auto_path b env errorCode errorInfo tcl_interactive tcl_libPath tcl_library tcl_patchLevel tcl_platform tcl_version

These globals have been defined:   a argc argv argv0 auto_path b env errorCode errorInfo tcl_interactive tcl_libPath tcl_library tcl_patchLevel tcl_platform tcl_version

localproc does not exist at point 1
localproc does exist at point 2

Local variables accessible in this proc are: loc1 loc2

Variables accessible from this proc are:     argv loc1 loc2

Global variables visible from this proc are: a argc argv argv0 auto_path b env errorCode errorInfo exist tcl_interactive tcl_libPath tcl_library tcl_patchLevel tcl_platform tcl_version


puts "This is how many commands have been executed: [info cmdcount]"
puts "Now  *THIS* many commands have been executed: [info cmdcount]"

puts "\nThis interpreter is revision level: [info tclversion]"
puts "This interpreter is at patch level: [info patchlevel]"

puts "The Pid for this program is [pid]"

proc factorial {val} {
  puts "Current level: [info level] - val: $val"
  set lvl [info level]
  if {$lvl == $val} {return $val;}
  return [expr ($val-$lvl) * [factorial $val]];
  }

set count1 [info cmdcount]
set fact [factorial 3]
set count2 [info cmdcount]
puts "The factorial of 3 is $fact"
puts "Before calling the factorial proc, $count1 commands had been executed"
puts "After calling the factorial proc, $count2 commands had been executed"
puts "It took [expr $count2-$count1] commands to calculate this factorial"

output:
This is how many commands have been executed: 333
Now  *THIS* many commands have been executed: 336

This interpreter is revision level: 8.6
This interpreter is at patch level: 8.6b1.2
The Pid for this program is 4740
Current level: 1 - val: 3
Current level: 2 - val: 3
Current level: 3 - val: 3
The factorial of 3 is 6
Before calling the factorial proc, 348 commands had been executed
After calling the factorial proc, 379 commands had been executed
It took 31 commands to calculate this factorial

proc demo {argument1 {default "DefaultValue"} } {
  puts "This is a demo proc.  It is being called with $argument1 and $default"
  }

puts "The args for demo are: [info args demo]\n"
puts "The body for demo is:  [info body demo]\n"

set arglist [info args demo]

foreach arg $arglist {
  if {[info default demo $arg defaultval]} {
    puts "$arg has a default value of $defaultval"
    } else {
    puts "$arg has no default"
    }
  }
Output;

The args for demo are: argument1 default

The body for demo is: 
  puts "This is a demo proc.  It is being called with $argument1 and $default"
 

argument1 has no default
default has a default value of DefaultValue


;# Set up a temporary file with a test proc.

set filename "C:\\windows\\temp\\TT_[pid]"
set outfile [open "$filename" "w"];


puts $outfile {set scr [info script]}
puts $outfile "proc testproc {} {"
puts $outfile "global scr;"
puts $outfile "puts \"testproc source file: \$scr.\""
puts $outfile "}"
puts $outfile {set abc 1};
puts $outfile {return};
puts $outfile {set aaaa 1};

close $outfile;

puts "This is the contents of $filename:"
puts ".............................................................."
puts "[exec  C:/Windows/system32/cmd.exe /C type $filename]"
puts ".............................................................."
puts "\n"

puts "Global variables visible before sourcing $filename:"
puts "[lsort [info globals]]\n"

;# Check that the proc does not exist, and source the file.

if {[info procs testproc] == ""} {
                puts "testproc does not exist.  sourcing $filename"
                source $filename
                }

;# run the proc.
puts "\nNow executing testproc"
testproc;

puts "Global variables visible after sourcing $filename:"
puts "[lsort [info globals]]\n"


;# Remove the extra file.
file delete $filename

output:

This is the contents of C:\windows\temp\TT_4740:
..............................................................

--------
Access is denied.
    while executing
"exec  C:/Windows/system32/cmd.exe /C type $filename"


;# Set up a temporary file with a test proc.

set filename "TT_[pid].tcl"
set outfile [open "C:/windows/temp/$filename" "w"];

puts $outfile "package provide tutordemo 1.0"
puts $outfile "proc demoproc {} {"
puts $outfile "puts {Running the demoproc}"
puts $outfile "}"
close $outfile;

pkg_mkIndex C:/windows/temp $filename

# With Tcl8.3, this must come after auto_mkindex.

lappend auto_path "C:/windows/temp"

puts "procedures matching demopr before package require are: [info proc demopr*]"
package require tutordemo
puts "procedures matching demopr after package require are: [info proc demopr*]"
demoproc
puts "procedures matching demopr after using deomproc : [info proc demopr*]"

# file delete C:/windows/temp/pkgIndex
# file delete $filename
Output:
procedures matching demopr before package require are:
procedures matching demopr after package require are: demoproc
Running the demoproc
procedures matching demopr after using deomproc : demoproc

# Using eval on a single command:
# Note the "list" command.  eval will discard one level of
# grouping - the quotes around the string.
eval [list puts "this is done with two arguments to eval"]

;# Using eval to define a proc

if {[string match [info procs newProcA] ""] } {
  puts "\nDefining newProcA for this invocation"
  set num 0;
  set cmd "proc newProcA "
  set cmd [concat $cmd "{} {\n"]
  set cmd [concat $cmd "global num;\n"]
  set cmd [concat $cmd "incr num;\n"]
  set cmd [concat $cmd " return \"/tmp/TMP.[pid].\$num\";\n"]
  set cmd [concat $cmd "}"]
  eval  $cmd
  }

puts "\nThe body of newProcA is: \n[info body newProcA]\n"

puts "newProcA returns: [newProcA]"
puts "newProcA returns: [newProcA]"

#
# Define a proc using lists
#

if {[string match [info procs newProcB] ""] } {
  puts "\nDefining newProcB for this invocation"
  set cmd "proc newProcB "
  lappend cmd {}
  lappend cmd {global num; incr num; return $num;}

  eval  $cmd
  }

puts "\nThe body of newProcB is: \n[info body newProcB]\n"
puts "newProcB returns: [newProcB]"

set arg1 {-nonewline {this will be }}
set arg2 {on a single line}

output:

The body of newProcB is:
global num; incr num; return $num;

newProcB returns: 3

Doesn't do what it says
-nonewline {this will be }
on a single line

Does what it says
this will be on a single line

;# This works
set cmd "OK"
eval puts $cmd

;# This also works
set cmd "puts" ; lappend cmd {Also OK}; eval $cmd

;# This generates an error
;# Change it to eval [list puts $cmd] to continue

set cmd "NOT OK"
eval puts $cmd

eval [format {%s "%s"} puts "Even This Works"]

set cmd "And even this can be made to work"

eval [format {%s "%s"} puts $cmd ]

set tmpFileNum 0;

;# Creating the tempFileName proc with lappend

set cmd {proc tempFileName }
lappend cmd "" 
lappend cmd "global num; incr num; return \"/tmp/TMP.[pid].\$num\""
eval  $cmd

puts "\nThis is the body of the proc definition:"
puts "[info body tempFileName]\n"

;# Now, show an incomplete command being caught by info complete

set cmd {puts "This is Cool!}

if {[info complete $cmd]} {
  eval $cmd
  } else {
  puts "INCOMPLETE COMMAND: $cmd"
  }

Output:
OK
Also OK

--------
can not find channel named "NOT"
    while executing
"realputs NOT OK"
    invoked from within
"$child eval realputs $args"
    (procedure "dummyputs" line 22)
    invoked from within
"puts NOT OK"
    ("eval" body line 1)
    invoked from within
"eval puts $cmd"


;# Some examples of subst:
set a "alpha"
set b a

puts {a and b with no substitution: $a $$b}
puts "a and b with one pass of substitution: $a $$b"
puts "a and b with subst in braces: [subst {$a $$b}]"
puts "a and b with subst in quotes: [subst "$a $$b"]\n"


puts "format with no subst [format {$%s} $b]"
puts "format with subst: [subst [format {$%s} $b]]"
eval "puts \"eval after format: [format {$%s} $b]\""

;# Creating the tempFileName proc with format

set num 0;
set cmd "proc tempFileName {} "
set cmd [format "%s {global num; incr num;" $cmd]
set cmd [format {%s return "/tmp/TMP.%s.$num"} $cmd [pid] ]
set cmd [format "%s }" $cmd ]
eval $cmd

puts "[info body tempFileName]"

;# An example where format works
set a arrayname
set b index
set c newvalue
eval [format "set %s(%s) %s" $a $b $c]

puts "Index: $b of $a was set to: $arrayname(index)"

output:
a and b with no substitution: $a $$b
a and b with one pass of substitution: alpha $a
a and b with subst in braces: alpha $a
a and b with subst in quotes: alpha alpha

format with no subst $a
format with subst: alpha
eval after format: alpha
global num; incr num; return "/tmp/TMP.4740.$num"
Index: index of arrayname was set to: newvalue

set dirs [list C:/windows C:/windows/system C:/temp C:/foo ]

puts "[format "%-15s  %-20s " "FILE" "DIRECTORY"]"

foreach dir $dirs {
  catch {cd $dir}
  set c_files [glob -nocomplain c*]

  foreach name $c_files {
    puts "[format "%-15s  %-20s " $name [pwd]]"
    }
  }
Output:
FILE             DIRECTORY           
CSC              C:/Windows          
Cursors          C:/Windows

proc errorproc {x} {
  if {$x > 0} {
    error "Error generated by error" "Info String for error" $x
    }
  }

catch errorproc
puts "after bad proc call: ErrorCode: $errorCode"
puts "ERRORINFO:\n$errorInfo\n"

set errorInfo "";
catch {errorproc 0}
puts "after proc call with no error: ErrorCode: $errorCode"
puts "ERRORINFO:\n$errorInfo\n"

catch {errorproc 2}
puts "after error generated in proc: ErrorCode: $errorCode"
puts "ERRORINFO:\n$errorInfo\n"

Output:
after bad proc call: ErrorCode: TCL WRONGARGS
ERRORINFO:
wrong # args: should be "errorproc x"
    while executing
"errorproc"

after proc call with no error: ErrorCode: TCL WRONGARGS
ERRORINFO:

after error generated in proc: ErrorCode: 2
ERRORINFO:
Info String for error
    (procedure "errorproc" line 1)
    invoked from within
"errorproc 2"

after proc that uses return to generate an error: ErrorCode: -999
ERRORINFO:
Return Generates This
    invoked from within
"returnErr 2"

after proc with an error: ErrorCode: TCL READ VARNAME
ERRORINFO:
can't read "a": no such variable
    while executing
"set x $a"
    (procedure "withError" line 2)
    invoked from within
"withError 2"

after an error call to a nonexistent file:
ErrorCode: POSIX ENOENT {no such file or directory}
ERRORINFO:
couldn't open "/no_such_directory/no_such_file": no such file or directory
    while executing
"open "/no_such_directory/no_such_file" "r""

Regexp Scenarios:
Scenario1:
set output {SNMP-COMMUNITY-MIB::snmpCommunityName.'public' = STRING: "public"
SNMP-COMMUNITY-MIB::snmpCommunitySecurityName.'public' = STRING: public
SNMP-COMMUNITY-MIB::snmpCommunityContextEngineID.'public' = Hex-STRING: 80 00 61 81 05 01
SNMP-COMMUNITY-MIB::snmpCommunityContextName.'public' = STRING:}

set output [split $output \n]

foreach ele $output {
   if {[regexp "SNMP-COMMUNITY-MIB::snmpCommunityName.*" $ele]} {
        regexp "STRING: \"(.*)\"" $ele match submatch
        set CommName $submatch
   }

   if {[regexp "SNMP-COMMUNITY-MIB::snmpCommunitySecurityName.*" $ele]} {
        regexp "STRING: (.*)" $ele match submatch
        set CommSecName $submatch
   }

   if {[regexp "SNMP-COMMUNITY-MIB::snmpCommunityContextEngineID.*" $ele]} {
        regexp "Hex-STRING: (.*)" $ele match submatch
        set EngineID $submatch
      } 
}

set runnconfig {SNMP-COMMUNITY-MIB snmpCommunityTable snmpCommunityEntry public
 snmpCommunityName            public
 snmpCommunitySecurityName    public
 snmpCommunityContextEngineID 80:00:61:81:05:01
 snmpCommunityContextName     ""
 snmpCommunityTransportTag    ""
 snmpCommunityStorageType     permanent}


set runnconfig [split $runnconfig \n]

foreach ele $runnconfig {
   if {[regexp "snmpCommunityName(.*)" $ele match submatch]} {
        set rCommName [string trim $submatch " "]
   }

    if {[regexp "snmpCommunitySecurityName(.*)" $ele match submatch]} {
        set rCommSecName [string trim $submatch " "]
   }

    if {[regexp "snmpCommunityContextEngineID(.*)" $ele match submatch]} {
        set rEngineID [string trim $submatch " "]
   }
}

set EngineID [join $EngineID :]
set resEngineID 0
if {$EngineID == $rEngineID} {
    set resEngineID 1
}


if {[string equal $CommName $rCommName] && [string equal $CommSecName $rCommSecName] && $resEngineID} {
    puts "Output of SNMP Walk matches with the running config"
} else {
    puts "Output of SNMP Walk doesnt match with the running config"
}

Scenario 2:
set output {SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."public" = OID: SNMP-USER-BASED-SM-MIB::usmHMACMD5AuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."initial" = OID: SNMP-USER-BASED-SM-MIB::usmNoAuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."initial_auth" = OID: SNMP-USER-BASED-SM-MIB::usmHMACMD5AuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."initial_authPriv" = OID: SNMP-USER-BASED-SM-MIB::usmHMACMD5AuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."initial_authPrivMD5AES" = OID: SNMP-USER-BASED-SM-MIB::usmHMACMD5AuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."initial_authPrivMD5DES" = OID: SNMP-USER-BASED-SM-MIB::usmHMACMD5AuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."initial_authPrivSHAAES" = OID: SNMP-USER-BASED-SM-MIB::usmHMACSHAAuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."initial_authPrivSHADES" = OID: SNMP-USER-BASED-SM-MIB::usmHMACSHAAuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserSecurityName."..a..."."initial_authPrivSHADES" = STRING: initial_authPrivSHADES
SNMP-USER-BASED-SM-MIB::usmUserCloneFrom."..a..."."initial_authPrivSHADES" = OID: SNMPv2-SMI::zeroDotZero
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."public" = OID: SNMP-USER-BASED-SM-MIB::usmHMACMD5AuthProtocol
SNMP-USER-BASED-SM-MIB::usmUserAuthProtocol."..a..."."initial" = OID: SNMP-USER-BASED-SM-MIB::usmNoAuthProtocol}

set output [split $output \n]

foreach ele $output {
   if {[regexp "SNMP-USER-BASED-SM-MIB::usmUserSecurityName.*" $ele]} {
        regexp "STRING: (.*)" $ele match submatch
        set usmUser $submatch
   }
}

set runnconf {SNMP-USER-BASED-SM-MIB usmUserTable usmUserEntry 80:00:61:81:05:01 initial_authPrivSHADES
 usmUserSecurityName initial_authPrivSHADES
 usmUserAuthProtocol 1.3.6.1.6.3.10.1.1.3
 usmUserPrivProtocol 1.3.6.1.6.3.10.1.2.2
 usmUserAuthKey      cc:e8:ca:d6:a1:26:3a:ad:f4:68:86:4d:59:3a:06:24:34:7c:c2:b1
 usmUserPrivKey      cc:e8:ca:d6:a1:26:3a:ad:f4:68:86:4d:59:3a:06:24}


set runnconf [split $runnconf \n]

foreach ele $runnconf {
   if {[regexp "usmUserSecurityName(.*)" $ele match submatch]} {
      set rusmUser [string trim $submatch " "]
   }
}

if {[string equal $usmUser $rusmUser]} {
    puts "UsmUser value matches"
} else {
    puts "UsmUser values doesnt match"
}

Scenario3:
set OP {
SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v1_trap' = STRING: std_v1_trap
SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v2_inform' = STRING: std_v2_inform
SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v2_trap' = STRING: std_v2_trap
SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v3_inform' = STRING: std_v3_inform
SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v3_trap' = STRING: std_v3_trap
SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v1_trap' = INTEGER: trap(1)
SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v2_inform' = INTEGER: inform(2)
SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v2_trap' = INTEGER: trap(1)
SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v3_inform' = INTEGER: inform(2)
SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v3_trap' = INTEGER: trap(1)
SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'std_v1_trap' = INTEGER: nonVolatile(3)
SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'std_v2_inform' = INTEGER: nonVolatile(3)
SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'std_v2_trap' = INTEGER: nonVolatile(3)
SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'std_v3_inform' = INTEGER: nonVolatile(3)
SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'std_v3_trap' = INTEGER: nonVolatile(3)
SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'std_v1_trap' = INTEGER: active(1)
SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'std_v2_inform' = INTEGER: active(1)
SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'std_v2_trap' = INTEGER: active(1)
SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'std_v3_inform' = INTEGER: active(1)
SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'std_v3_trap' = INTEGER: active(1)
}

set OP [split $OP \n]

foreach ele $OP {
   #SNMP Notify Tags
   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v1_trap'.*STRING: (.*)" $ele match submatch]} {
      set SNMP_Notify_Tag1 $submatch
   }

   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v2_inform'.*STRING: (.*)" $ele match submatch]} {
      set SNMP_Notify_Tag2 $submatch
   }
  
   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v2_trap'.*STRING: (.*)" $ele match submatch]} {
      set SNMP_Notify_Tag3 $submatch
   }

   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v3_inform'.*STRING: (.*)" $ele match submatch]} {
      set SNMP_Notify_Tag4 $submatch
   }

   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'std_v3_trap'.*STRING: (.*)" $ele match submatch]} {
      set SNMP_Notify_Tag5 $submatch
   }

   #SNMP Notify Types
   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v1_trap'.*INTEGER: (.*)" $ele match submatch]} {
      regsub {\([0-9]*\)} $submatch "" SNMP_Notify_Type1
   }

   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v2_inform'.*INTEGER: (.*)" $ele match submatch]} {
      regsub {\([0-9]*\)} $submatch "" SNMP_Notify_Type2
   }

   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v2_trap'.*INTEGER: (.*)" $ele match submatch]} {
      regsub {\([0-9]*\)} $submatch "" SNMP_Notify_Type3
   }

   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v3_inform'.*INTEGER: (.*)" $ele match submatch]} {
      regsub {\([0-9]*\)} $submatch "" SNMP_Notify_Type4
   }

   if {[regexp "SNMP-NOTIFICATION-MIB::snmpNotifyType.'std_v3_trap'.*INTEGER: (.*)" $ele match submatch]} {
      regsub {\([0-9]*\)} $submatch "" SNMP_Notify_Type5
   }
}

set RC {
SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v1_trap
 snmpNotifyTag  std_v1_trap
 snmpNotifyType trap
!
SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v2_inform
 snmpNotifyTag  std_v2_inform
 snmpNotifyType inform
!
SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v2_trap
 snmpNotifyTag  std_v2_trap
 snmpNotifyType trap
!
SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v3_inform
 snmpNotifyTag  std_v3_inform
 snmpNotifyType inform
!
SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v3_trap
 snmpNotifyTag  std_v3_trap
 snmpNotifyType trap
!}

set RC [split $RC !]

foreach ele $RC {
   if {[regexp {SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v1_trap} $ele]} {
        regexp {snmpNotifyTag  ([0-9a-z\_]*)} $ele match Rtag1
        regexp {snmpNotifyType ([0-9a-z\_]*)} $ele match Rtype1
   }

   if {[regexp {SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v2_inform} $ele]} {
        regexp {snmpNotifyTag  ([0-9a-z\_]*)} $ele match Rtag2
        regexp {snmpNotifyType ([0-9a-z\_]*)} $ele match Rtype2
   }

   if {[regexp {SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v2_trap} $ele]} {
        regexp {snmpNotifyTag  ([0-9a-z\_]*)} $ele match Rtag3
        regexp {snmpNotifyType ([0-9a-z\_]*)} $ele match Rtype3
   }

   if {[regexp {SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v3_inform} $ele]} {
        regexp {snmpNotifyTag  ([0-9a-z\_]*)} $ele match Rtag4
        regexp {snmpNotifyType ([0-9a-z\_]*)} $ele match Rtype4
   }

   if {[regexp {SNMP-NOTIFICATION-MIB snmpNotifyTable snmpNotifyEntry std_v3_trap} $ele]} {
        regexp {snmpNotifyTag  ([0-9a-z\_]*)} $ele match Rtag5
        regexp {snmpNotifyType ([0-9a-z\_]*)} $ele match Rtype5
   }
}

#Compare Values of SNMP Notify Tag
if {[string equal $SNMP_Notify_Tag1 $Rtag1] && [string equal $SNMP_Notify_Tag2 $Rtag2] && [string equal $SNMP_Notify_Tag3 $Rtag3] && [string equal $SNMP_Notify_Tag4 $Rtag4] && [string equal $SNMP_Notify_Tag5 $Rtag5]} {
   puts "Values of SNMP Notify Tag matches with running configuration"
} else {
   puts "Values of SNMP Notify Tag does not match with running configuration"
}

#Compare Values of SNMP Notify Type
if {[string equal $SNMP_Notify_Type1 $Rtype1] && [string equal $SNMP_Notify_Type2 $Rtype2] && [string equal $SNMP_Notify_Type3 $Rtype3] && [string equal $SNMP_Notify_Type4 $Rtype4] && [string equal $SNMP_Notify_Type5 $Rtype5]} {
   puts "Values of SNMP Notify Type matches with running configuration"
} else {
   puts "Values of SNMP Notify Type does not match with running configuration"
}















































No comments:

Post a Comment