PreviousNext

Creating New Commands

The dcecp program provides a powerful and comprehensive set of commands for controlling and monitoring DCE operations. But the exact uses to which DCE is put by end users is unpredictable. Consequently, it's quite likely that some administrators will need additional commands to meet very specific needs. The proc command offers an easy way to create additional commands which look and behave just like built-in commands such as set, list, and while. But unlike built-in commands which are written in C, commands created with proc are written using scripts as in:

dcecp> proc div {x y} {expr $x/$y}
dcecp>

proc takes three arguments: the procedure name, a list of names of procedure arguments, and the dcecp script that forms the body of the new procedure. Our new procedure div requires two arguments. For example,

dcecp> div 12 4
3
dcecp>

By default proc assumes all variables are local variables. That is, their names and values are set only within the procedure and they expire when the procedure completes. The following command produces an error because variables x and y have not been set within the procedure.

dcecp> set x 15
15
dcecp> set y 3
3
dcecp> proc div {} {expr $x/$y}
dcecp> div
Error: can't read "x": no such variable

You can import global variables (variables defined outside the procedure) using the global command:

dcecp> set x 15
dcecp> set y 3
dcecp> proc div {} {
> global x y
> expr $x/$y
> }
dcecp> div
5
dcecp>

Once you import a global variable, it persists for the duration of the procedure. Your procedure can change the value of the variable using unset and set. The new value will be available for use inside and outside of your procedure.

You can use the return command to make your procedure return immediately. The value of the argument to return becomes the procedure's return value.

proc find {a} {
<some pattern matching script that looks for a specific CDS entry>
if {a != b} {
return 1
}
return 0
}

You can design procedures to take no arguments or variable numbers of arguments. For instance a procedure with no arguments could simply perform some straightforward operation as in the following example.

proc _do_create_group {} {
global rpcgroupname
rpcgroup create $rpcgroupname
}

You can also specify a default value for an argument using a nested list structure in the argument list. In the following example, the first argument attr must be supplied. The second argument, value, defaults to unset if no argument is supplied.

proc _attr_show {attr {value "unset"}} {
puts "$attr is $value"

}

Procedures can call other procedures. The current procedure can import variables from any calling procedure using the upvar command.

upvar level otherVar1 myVar1 otherVar2 myVar2

A level argument of 1 gets the variable context of the parent procedure. An argument of 2 gets the variable context of parent's parent procedure. You can also specify levels relative to the global context by preceding the level argument with #. A level of #0 gets global variables. A level of #1 gets variables from a procedure invoked from the global level.

The otherVar argument names the variable you want to import. You need to include the myVar argument to rename the variable for use in the current procedure. The following example renames the imported variable to cargs.

upvar 1 local_args cargs

Procedures can also execute scripts under the context of parent procedures using the uplevel command. This command offers a convenient way to manage your procedure's context. For instance, rather than import and manipulate numerous variables from a parent procedure, use uplevel to connect to them all at once. The syntax is:

uplevel level arg arg arg

The uplevel command is similar to eval; it concatenates arguments and executes them as scripts but unlike eval, uplevel executes the script in the context specified by level rather than the current context. The level argument works the same in uplevel as it does in upvar. Use the parent's context using a level argument of 1. Use the context of a first level procedure using a level argument of #1.

If a proc command specifies a command name that is already in effect, the new procedure replaces the existing procedure with the same name. Except in unusual cases, you should avoid naming new commands so that they replace existing built-in commands.

You can rename or delete Tcl commands using the rename command. For instance you could temporarily rename list to list.old and then use proc to create another command called list. When you're through using the manufactured list command, you could rename list old to list, restoring the original function of list as in:

rename list list.old
proc list {} {
<some list operation>
}
rename list.old list

Delete a command by omitting the second argument to the rename command. The following example deletes the list command.

rename list