Amanda Portal System Reference Manual

0 (0)

Amanda Portal System Reference Manual

Version 1.27E

The Amanda Company, Inc.

January 9, 2003

Contents

1

Introduction

5

 

1.1

Core Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

 

1.2

Tcl As An Extensible Glue Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

 

 

1.2.1 An Introduction to Tcl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7

 

 

1.2.2

Tcl and Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

 

 

1.2.3

Tcl and State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

 

 

1.2.4 Assigning Scope to Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

 

1.3

Control Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

 

1.4

Waiting for Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

 

1.5

Loadable DLLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

 

1.6

Resource Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

36

2

Security Model

40

 

2.1

Ancestors and Descendents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

 

2.2

Privileges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

 

2.3

Login and Logout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

44

3

How Amanda Portal Interacts with Telephone Switches

46

4

Mailboxes

 

49

 

4.1

Box Manipulation Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

50

 

4.2

Box Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

54

1

5

Multimedia Objects (MMOs)

63

 

5.1

Messages and Folders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

70

 

5.2

MMO Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

80

 

5.3

Announcements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

84

 

5.4

Published MMOs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

88

6

Voice and Fax Devices

90

 

6.1

OOP Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

90

 

6.2

Interconnection Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

91

 

6.3

Make

 

local and Default Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

91

 

6.4

Network Device Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

93

 

6.5

VP Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

98

 

6.6

Port Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

109

 

6.7

Miscellaneous Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

110

7

Fax Commands

113

8

Internet E-Mail

115

9

Serial Devices

121

10

Miscellaneous Databases

125

 

10.1

List Mapping Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

125

 

10.2

Trie Mapping Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

129

11

The Configuration Database

133

12

Triggers

138

 

12.1

Autoschedules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

138

 

12.2

Notifications and the Job Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

141

 

 

12.2.1 The Notify Record Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

142

2

12.2.2 The Notify Instance (Job Queue) Database . . . . . . . . . . . . . . . . . . . . . . . . 144 12.2.3 The Notify Template Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 12.3 Data Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

13

Persistent Procedures

162

14

Integration

164

 

 

14.0.1 Serial Integration Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

166

15

Call Queueing

168

16

Connecting to External Databases (ODBC)

191

17

Miscellaneous

197

 

17.1

The tokens Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

200

 

17.2

Time Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

203

 

17.3

Terminating Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

206

 

17.4

Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

207

 

17.5

Speech Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

208

 

17.6

Web Client Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

211

 

17.7

TCP Client Connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

212

 

17.8

VoIP Appliance Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

213

 

17.9

COM/OLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

217

A

Error Codes and Messages

218

3

Preface

In all of the function definitions in this document, if there is a ‘*’ next to the function name, you can execute the function when you aren’t logged in. Otherwise, you must be logged into the system. In a related vein, many functions have the notion of a current box. When you don’t give the -box option, they operate on the current box. When you are not logged in, there is no notion of a current box and these functions require the -box option.

Commands syntax is verb noun. Normally, if a command can return one or more results, the ‘s’ su x is left o the command (e.g., set box setting rather than set box settings). This makes it easier for the programmer to remember the name of the command. Commands that require a box parameter (e.g., is box) do not use the -box syntax; the box is simply given as a required parameter. The -box syntax is for options only.

A fundamental theme in Amanda Portal is the notion of the box hierarchy and permissions related to the box hierarchy. Boxes create other boxes in an ancestral tree structure. Generally, unless specified otherwise, boxes only have permission to modify their box settings and the settings of their descendents. They cannot modify the setting of their proper ancestors.

Every command in this document can get a “usage” error if you call the command wrong. In this case, errorCode will be set to USAGE and interp->result will be the usage of the function.

Many commands in this system may process half an argument list before discovering an error. This means that half of the arguments changed values in the database and the other half didn’t. Care is taken to alleviate this problem as much as possible though, for example, by checking the syntax of the arguments before executing transactions against the database.

4

Chapter 1

Introduction

The Amanda Portal system consists of a core set of functionality, which defines basic building blocks from which a variety of call processing systems can be built. A variety of plug-in modules, in the form of Windows DLLs, can be installed which augment the functionality of the core. By using plug-in DLLs, a system can be configured to load only the code and features that it requires. Since third parties can also develop these DLLs, there is a great deal of flexibility and extensibility in the system. The core and the plug-in modules together define an API which is similar to that of an operating system. They define a security model, provide networking features, etc.

Above this “API” layer is a scripting language, the Tool Command Language (Tcl), which is now familiar to over one million programmers world-wide. The scripting language serves two di erent purposes:

1.It acts as a “glue” to tie together the functionality of the di erent loadable modules (DLLs). As such, it acts as a very high level language for voice processing needs.

2.It allows quick and easy customization of an existing system, or rapid development of whole new voice processing solutions. The entire Amanda@Work.Group Telephone User Interface (TUI) consists of only a few thousand lines of Tcl code.

This architecture has several advantages:

It separates functionality (how a particular task is implemented) from behavior (why a particular task should happen, such as a certain sequence of DTMF digits were input by a user).

Because Tcl is the only interface to the system, network and telephone clients use exactly the same interface to accomplish tasks within the system. There is exactly one function which can be used to send voice mail to a mailbox, for instance; this function is used by all types of clients.

Because the functionality is implemented in C++, it operates very e ciently, while the telephone user interface is scripted because this is where a great deal of flexibility is required. The TUI Tcl script is basically just implementing flow of control across all the possible functional calls (record, play, get digits, send voice mail, etc.).

Since all the functionality is implemented in C++ and is not maliable, it is possible to implement a secure system. Users are allowed to execute any Tcl commands that are made available to them but cannot side-step the security model that is built into the system at the lower level.

5

This architecture allows the TUI to be completely flexible without having to reimplement any functionality at lower levels. For instance, it would be quite possible to build a speech-recognition based voice mail system which would be quite di erent from the DTMF-based, Amanda@Work.Group-like interface that is currently provided. The menuing system would presumably be much “flatter,” but the underlying features such as sending and listening to voice mail, changing mailbox settings, etc., would remain exactly the same at the C++ level.

1.1Core Features

The core module implements a number of fundamental objects in the system: mailboxes, MultiMedia Objects (MMOs), a number of databases (the MMO lookup table, the voice mailbox database, etc.), an autoscheduler, a notifier and outbound call job management system, etc.

As part of the system’s security model, mailboxes are arranged in a hierarchy. Every mailbox has a “parent” mailbox which is the one which created it. A mailbox may be given the right to create subordinate, or children, mailboxes. A top-level mailbox’s parent is itself, since no mailbox created it, and such a box is referred to as a superbox in this manual. Such a mailbox is given certain special privileges in Amanda Portal, similar to the “root” user on a Unix system. Unlike Unix, however, there can potentially be more than one top-level mailbox (a “forest” of mailbox trees), although it is unlikely that this feature will be needed in practice.

Mailboxes have several components: they have some settings (the list of settings is extensible to make development of new applications more flexible), they have a set of privileges which have known semantics to the core, they may have messages which they have received, and the messages in turn may have zero or more MMOs associated with them. Boxes may “publish” MMOs for others to use, such as greeting recordings. Boxes can establish autoschedule and notify records which cause the system to execute Tcl code on their behalf when certain events happen or certain times arrive.

1.2Tcl As An Extensible Glue Language

Tcl makes a good embedded systems language because it is high-level, easy to extend the language by adding C functions as Tcl primitives and has security mechanisms built in using the nested interpreter model and “code injection”1. Nested interpreters give you an operating system like “system call” interface where you write your “system calls” in Tcl. In this model, the system calls always exist in your interpreter. If you are not allowed to perform a call, the system call returns an error. The master interpreter operates in “kernel” mode and the slave interpreter operates in “user” mode.

Code injection works slightly di erently. The protected calls you need to use don’t check whether you have permission to execute them; instead, the calls don’t exist in your interpreter until a specified event happens (such as you log in). At this point, the call is inserted into your interpreter and you can use the new calls. When you log out, the calls are removed from your interpreter.

Tcl is a Lisp like language so writing code with it is quite “functional.” You often write code like

eval modify elements [get elements handle]

1A tAA defined term.

6

where get elements returns the operands to operate on as a Tcl list and modify elements operates on those operands. Tcl also helps extensibility by being interpreted. This means that you can add code on the fly to your program and modify the behavior of the code shipped with the system. Tcl also has associative arrays built in; these are the regular Tcl array variables. Internally, they are implemented as hash tables so lookup on them is very speedy. Multi-dimensional arrays can be simulated in Tcl by using concatenated indices in regular arrays.

1.2.1An Introduction to Tcl

Safe interpreters are simply regular interpreters with certain “unsafe” calls removed; that is, they are interpreters where some unsafe code has already been “dejected.” All Tcl interpreters in Amanda Portal are of the “safe” variety, and as such, they have only the following standard Tcl commands: append, array, break, case, catch, concat, continue, error, eval, expr, for, foreach, format, gets, global, if, incr, info, interp, join, lappend, lindex, linsert, list, llength, lower, lrange, lreplace, lsearch, lsort, proc, regexp, regsub, return, scan, set, split, source, string, switch, time, trace, unset, uplevel, upvar, and while.

This subsection gives a brief description of each of these commands. Those who are already familiar with Tcl should skip ahead to the next section. There are many books available which cover the Tcl language, including Tcl and the Tk Toolkit, by Tcl’s author, John Ousterhout, and Tcl For Dummies, in the famous “Dummies” series. While those books should be consulted for in-depth examples, they also cover many more features of Tcl, plus the Tk graphical extensions, which are not used in Amanda Portal.

Tcl Variables

Programming languages contain two fundamental elements: variables and procedures. Object-oriented languages combine these two features into objects (naturally). Variables in Tcl have three attributes:

name The variable’s name allows access to its contents.

scope The scope of a variable determines how long it will live. When it goes out of scope, a variable is automatically destroyed.

value Finally, each variable has a value.

In many programming languages, variables have a fourth attribute, a type, which determines the kind of data that the variable can have as its value, the size of the date (range of values, length of a string, etc.). In these languages, variables are declared, and a variable can exist without having a defined value.

Tcl’s variables, like those of Amanda@Work.Group, do not have a specific type. Internally, they are all represented as strings and are converted on-the-fly as needed to other types (floating point, integer) when necessary. This feature makes Tcl programming easier. A variable springs into existence the first time it is used. This also means that it’s impossible to have a variable which does not have any value.

To create a variable in Tcl, you use the set command, like this:

set variable value

For example, to set the variable myname to Tim, you would simply type

7

set myname Tim

To access the value of a variable, put a dollar sign in front of its name. For sample, to copy the value of the variable myname to a second variable called firstname, you would type

set firstname $myname

This process is called variable substitution: the name of the variable is replaced by its value.

Each executable statement in Tcl consists of a single command line, which is terminated with a newline or a semicolon. For instance,

set x 14 set y 27

could just as easily be written

set x 14; set y 27

Tcl evaluates each command line using a two-step process: parsing and execution. During parsing, the command line is divided into space-separated arguments, then variable substitution and other processing is performed on the arguments. At this point, Tcl doesn’t attach any meaning to the arguments themselves; it’s just doing simple string substitutions.

In the execution step, the first argument of the line is treated as a command name to be run. The other arguments on the command line are passed on to the command, which will apply meaning, if any, to them. The command will return a string value as the result of its processing. In each of the examples above, the command name was set.

What would happen if you tried to execute the command

set name Tim Morgan

This is a problem because set will see three arguments rather than the two it’s expecting (a variable to set and a value to set it to). Just as in Amanda/DOS, we can overcome this problem by using quotation marks to “hide” the space from the parser:

set name "Tim Morgan"

Now suppose that we have two variables, firstname and lastname, and what we need is the person’s full name. We can achieve this by writing

set name "$firstname $lastname"

8

On the other hand, if we write

set name {$firstname $lastname}

then no variable substitution will be performed. We can also mix and match:

set salary "$firstname $lastname \$30,000"

This would expand the values of firstname and lastname, but it would leave the dollar sign before 30,000.

Be careful of the following types of commands:

set x 4 set y x set z x+y set $y 5

The first sets x to 4, as expected, but the second command sets y to the string x, not to the value of x.

Remember that Tcl does not associate any meaning with the arguments as it parses them. Therefore, the third command simply sets variable z to the string x+y. We’ll learn how to accomplish addition shortly.

The last command sets x to 5, not y.

We have already seen an example of backslash substitution when we used $ to produce a literal dollar sign character in a string. Many of the backslash substitutions are the same as those in Amanda/DOS:

Symbol

Meaning

\a

Audible alert (bell)

\b

Backspace

\f

Formfeed

\n

Newline

\r

Return

\t

Tab

\v

Vertical tab

\ddd

Octal value

\xhh

Hex value

\newline

Single space

\$

Dollar sign

\\

Backslash

\[

Open square bracket

Tcl Lists

A Tcl list is an ordered collection of strings. In its simplest form, a list is simply a string, with spaces separating the list’s elements. In this case, the elements cannot contain spaces.

Lists are usually written surrounded by curly braces. Sublists, or elements with spaces, are denoted by inner braces. For example,

9

set x {a b {c d e} f}

sets x to a list containing four elements. The third element is the list (or string) c d e.

Tcl contains a number of built-in functions for manipulating lists.

Built-In Commands and Procs

So once the command to execute has been determined, and Tcl knows what the arguments are, what happens next? Tcl will look up the command name to verify that it’s valid. If it isn’t, then an error is generated.

If it is a valid command, then there are two possibilities: the command is a “built in” one or it’s a “Tcl procedure.”

Commands (procedures, or “procs”) which you define in Tcl are indistinguishable from the built-in commands, except that the built-in ones are faster and can access operating system and device driver level calls.

A “built in” Tcl command has its underlying implementation in C. In this case, Tcl invokes the corresponding C procedure and processing of the command is done in compiled code. The set command is a built-in, for example.

Tcl defines a number of built-in commands, and applications using Tcl can define additional built-in commands. Not surprisingly, Amanda Portaldefines quite a few application-specific commands which will be covered in the Amanda PortalProgramming class.

So far, we’ve seen two kinds of substitutions which happen automatically to commands: variable and backslash. We also know that all Tcl commands (procedures) return a value. This leads to the third type of substitution, command substition. To illustrate it, we’ll introduce another built-in command, expr.

Expressions

The expr command concatenates all its arguments into one long string, then it evaluates that string as an expression, and it returns the resulting value as its procedure value (remember that all procedures return a value in Tcl).

Here are some example interactions with Tcl:

%expr 2*3

6

%set x 4

4

%expr $x * 7

28

%expr ($x * $x) / 2

8

10

Now we’re ready to discuss the third type of substitution, command substitution. Recall that every command returns a string result. Command substitution allows us to replace a complete Tcl command with its result for use in an enclosing command. To use it, just enclose a command inside square brackets: []. For example:

%set x 4

4

%set y 7

7

%set z [expr $x * $y]

28

Arrays

So far, the variables we’ve used have been simple variables, also called scalar. Tcl also provides another kind of variable, called an associative array. An associative array is a collection of di erent values which are indexed by a string (the element name). This is a very powerful mechanism, and associative arrays are used extensively in Amanda Portal.

Array elements thus have two names: the name of the array plus the name of the element. The element name is enclosed in parentheses. It may be a constant or a variable (or a combination), so long as it doesn’t contain a space. If the element name has a space, then the entire variable name must be quoted to “hide” the space.

For example, we could collect information on a person this way:

set person(name) "Tim Morgan" set person(age) 37

set person(address) "23822 Brasilia Street" set person(city) "Mission Viejo"

set person(state) California set person(zip) 92691

On the other hand, if we have information about a number of people, we might use one array per attribute, and use the names as the indices:

set age(Tim) 37

set address(Tim) "23822 Brasilia Street" set city(Tim) "Mission Viejo"

set state(Tim) California set zip(Tim) 92691

set age(Siamak) 36

set address(Siamak) "26321 Eva Street" set city(Siamak) "Laguna Hills"

set state(Siamak) California set zip(Siamak) 92656-3108

We can use the values in the array pretty much just as with simple variables:

11

%set foo $age(Tim)

37

%set name Tim

Tim

%set foo $age($name)

37

%set foo [expr $age(Tim) + $age(Siamak)]

73

Besides set, Tcl defines a few other built-in functions for working with variables:

append Appends one or more values to a variable.

incr Adds a value to an existing numeric variable.

unset Deletes one or more variables.

array Returns various information about array variables.

The syntax for the append command is as follows:

append varname value . . .

If varname is an existing variable, then value will be appended to it, as will any additional values.

If varname didn’t exist previously, then it is set to value as if the set command had been used.

Like set, append returns the new value of varname as its result.

The incr command is exactly like the + token in Amanda/DOS. It allows you to do an arithmetic addition to an existing numeric variable. The value added may be positive or negative, and it defaults to 1.

%set i 1

1

%incr i

2

%incr i 2

4

%incr i -3

1

The variable must exist and have an integer value. The incr function returns the new value as its result.

The unset command is used to delete a variable and its associated value(s). If an array variable is deleted, then all of its elements are deleted. The general syntax for the command is:

unset var . . .

12

The unset command always returns an empty string as its result:

%set age(Tim) 37

37

%set age(Siamak) 36

36

%unset age

%

The Array Command

The array command allows you to obtain information about a Tcl array. The general syntax is:

array cmd name args

where cmd is a special keyword for the array command. Some of the available keywords are:

names ary Returns a Tcl list of the names (valid indices) for array ary.

size ary Returns the number of elements in array ary.

exists var Returns whether var exists and is an array.

get name pattern Returns a list of pairs of element names and values from the array name. If pattern is specified, then only those elements whose names match pattern will be returned. A list of name and value pairs is called an a-list.

set name list Sets elements of the array name from list which should be of the same form as is returned by array get.

Normally, the array command will be used in conjunction with command substitution along with some other commands which we’ll examine next week. In the mean time, here are some standalone examples of array, using the age array we defined earlier:

%array size age

2

%array names age Tim Siamak

Notice that the result of the array names command will list the names in arbitrary order. If you want it sorted a particular way, you can use the lsort command discussed on page 16.

Tcl Expressions

Expressions combine values with operators to produce a new value. Simple examples follow everyday arithmetic rules. For example:

13

% expr (8+4) * 6.2 74.4

%

In addition to the usual binary operators +, -, *, and /, there are a number of other important unary and binary operators (and there are some less important ones which we won’t mention). There’s also %, which computes the remainder from a division (this is the “mod” or “modulo” operator).

Most operators are called binary because they work on two values. For instance, + is a binary operator since it is used to add two di erent values, which are written on either side of it.

Unary operators, in contrast, are operators which work on a single value which comes after the operator. The most familiar one of these is unary minus, which negates the value of its operand.

%set x 4

4

%set y [expr -$x]

-4

The other important unary operator is logical not, which is written !. It changes true values to false, and false values to true.

In Tcl, as in C, logical values are represented as numeric values. A false value is represented as 0, while a true is any non-zero value. Therefore,

%set x 4

4

%set y [expr !$x]

0

%set x [expr !$y]

1

Relational operators are binary operators to compare one value to another. They all work on integer, real (floating point), and string values.

Syntax

Result

a<b

1

if a < b else 0

a>b

1

if a > b else 0

a<=b

1

if a ≤ b else 0

a>=b

1

if a ≥ b else 0

a==b

1

if a = b else 0

a!=b

1

if a 6= b else 0

Often you want to combine the results of more than one logical test. The logical operators allow you to do so. They follow the same syntax as in the C language.

14

Logical and is represented as &&. The expression a&&b is true (1) if both the expressions a and b are non-zero, and zero otherwise.

Logical or is represented as ||. The expression a||b is true (1) if either of the expressions a or b is true, and zero otherwise.

As in C, these operators are short-circuit: the second operand is not evaluated if the first shows the result of the whole thing.

Here are some examples of logical operators:

%set a 1

1

%set b 0

1

%expr a&&b

0

%expr a || b

1

%expr b || a

1

%expr b && exp(sin(sqrt(2.0))) > 4

0

%expr a || exp(sin(sqrt(2.0))) > 4

1

In the last two examples, function foo is not called, because the result can be determined from the value of the first argument alone.

List Commands

Tcl defines quite a few commands for operating on lists. We’re going to look at the following ones:

lindex Retrieves individual elements from a list.

llength Returns the length of a list.

lsort Returns a new list resulting from sorting an existing list.

lappend Appends new items to an existing list (variable).

split Returns a list by spliting up a string at each point where a given substring occurs.

The lindex function returns as its value an element of a list. The general syntax is:

lindex list index

The index must evaluate to an integer. The first element of the list is number 0. For example:

15

%set mylist {a b {c d e} f} a b {c d e} f

%lindex $mylist 1

b

%lindex $mylist 2 c d e

%set x {a b c d e} a b c d e

%lindex $x 4

e

%

The llength function simply returns the number of elements in a list. Its syntax is

llength list

Continuing from the previous example:

%llength $x

5

%llength $mylist

4

%set len [llength [lindex $mylist 2]]

3

The lsort command returns a new list which is created by sorting an existing list. The syntax is:

lsort flags list

The flags parameter can be a combination of a type and a direction. The types are:

-integer Treat the list elements as integers.

-ascii Treat the list elements as strings (default).

-real Treat the list elements as floating point (real) numbers.

The direction can be one of the following:

-increasing Sort the items in ascending order (default).

-decreasing Sort in decending order.

Here are some examples of lsort:

16

%set x {22 12 9 97} 22 12 9 97

%lsort $x

12 22 9 97

%lsort -integer $x 9 12 22 97

%set sorted_list [lsort -integer $x] 9 12 22 97

The lappend command appends one or more values to a variable as list elements. It creates the variable if it doesn’t already exist. It di ers from append because with lappend, the items are appended with separating spaces and will be given braces where necessary to keep items separate; append simply appends each string as-is.

The general syntax is:

lappend varname value . . .

The lappend function returns the new value of varname as its result value.

Here are some examples:

%set x {a b c} a b c

%lappend x d e f a b c d e f

%lappend x "Tim Morgan" "Carl Doss" a b c d e f {Tim Morgan} {Carl Doss}

%llength $x

8

%

Notice that in the second lappend command, two values are being appended. This is reflected in the result of llength: there are eventually 8 items in the list.

The split command creates a new list by splitting up a string. You can specify a set of separator characters as the second argument, or let it default to standard white-space characters.

%split "abc/def/ghi" "/" abc def ghi

%split "abc.def/ghi" "/." abc def ghi

17

Amanda Portal System Reference Manual

*linsert

Description

linsert can be used to insert items into an existing list variable at a particular index.

*lrange

Description

lrange can be used to extract a range of items from a list (returning a new list).

*lreplace

Description

lreplace can be used to create a new list from and old list with a range of items replaced by a new set of items (not necessarily the same number of items).

Eval

One final note on parsing. Sometimes you have a list of items in a variable, and you want to pass that list as arguments to some command, such as lappend. Here’s an example of the problem:

%set mylist {a b c} a b c

%set additional_items {d e f} d e f

%lappend mylist $additional_items a b c {d e f}

What we really wanted was to get a resulting list of {a b c d e f}, not {a b c {d e f}}. The eval command lets us solve this and other similar problems.

18

The eval command takes one or more arguments and concatenates them into one long string. It then evaluates (executes) this string as as a Tcl command. Let’s look at how we’d use eval in the previous example:

%set mylist {a b c} a b c

%set additional_items {d e f} d e f

%eval lappend mylist $additional_items a b c d e f

Why does this work? The eval command sees three arguments: lappend, mylist, and a string “d e f” (the quotation marks aren’t part of the string). It appends all of these strings together, with separating spaces, arriving at the new command string “lappend mylist d e f” (again, the quotation marks aren’t part of the string). Then eval executes the command, and mylist gets three new elements instead of one sublist element.

Control Flow

Normally, a program is executed sequentially, one statement after the previous one. Most programming languages, including Tcl, provide two basic ways to vary this.

Branching means skipping to or past some statements. This is provided with the if and switch commands.

Looping allows a set of statements to be repeated zero or more times. This is provided by the while, for, and foreach commands, along with their helper commands break and continue.

The general syntax for the if statement is:

if test1 body1 [elseif test2 body2 . . . ] [else bodyN]

The testn values may be any expression which evaluates to a Tcl boolean value (zero or non-zero). Typically, they will include relational operators. The bodyn values may be any Tcl statement or list of statements. Remember that statements may be separated by semicolons or returns, and uninterpreted lists may be written using curly braces, and they “hide” any embedded returns.

19

This means you can write statements like:

if {$x < 0} "set x 0"

if {$x < 0} {set x 0; set y 7} if {$x < 0} {

set x 0 set y 7

}

But you may not write

if {$x < 0}

{

set x 0

}

The most common way to write if statements is like this:

if {$x < 0} {

...

}elseif {$x == 0} {

...

}elseif {$x == 1 && $y == 7} {

...

}else {

...

}

The switch statement allows you to match a string against a number of patterns, and if a match is found, to execute some code. The pattern matching may be one of:

-exact The strings must match exactly.

-glob Wildcards * and ? can be used, just like the DOS DIR command; this is the default).

-regexp Regular expression pattern matching is applied—see the manual for details.

Suppose that you want to test $x to see if it’s any of the strings a, b, or c. You could do this with if:

if {$x == "a"} { incr t1

}elseif {$x == "b"} { incr t2

}elseif {$x == "c"} {

incr t3

}

20

With the switch statement, you can write this more clearly:

switch $x {

a {incr t1} b {incr t2} c {incr t3}

}

While while statement’s syntax is:

while test body

Here’s an example of reversing a list a, putting the result into list b:

%set a {1 2 3 4 5 6} 1 2 3 4 5 6

%set b {}

%set i [expr [llength $a] - 1]

6

%while {$i >= 0} {

lappend b [lindex $a $i] incr i -1

}

-1

% set b

6 5 4 3 2 1

%

The for statement is usually used to perform a loop for a specified number of times, using a control variable to count the number of iterations. The Tcl syntax, like that of C, is more general:

for init test reinit body

The for statement executes the init statement. Then while the test is true, it executes body and reinit. Thus, for is really a while statement with a few other statements thrown into the mix. You can accomplish the same things with either statement. When a loop is controlled by a variable, then using for will result in more easily understood code.

21

To iterate variable i from 1 to 10, you would write

for {set i 1} {$i <= 10} {incr i} { set array($i) "This is item $i"

}

To reverse list a, putting the results in b:

set b {}

for {set i [expr [llength $a] - 1]} { $i >= 0} {incr i -1} {

lappend b [lindex $a $i]

}

The foreach statement is used very frequently in Tcl. It iterates a control variable through each item in a Tcl list, executing a body of statement(s) each time. So to reverse a list, one could write

set b {} foreach i $a {

set b [linsert $b 0 $i]

}

To reset each element of an array to an empty string, one could write:

foreach i [array names a] { set a($i) ""

}

Sometimes you want to leave a loop or repeat a loop from somewhere in its interior. This is the purpose of the break statement. Suppose you know that ary(n) is equal to 7, for some value of n. To determine n, you could write:

foreach i [array names ary] { if {$ary($i) == 7} {break}

}

#At this point, $i is the index into

#"ary" for the value "7"

Using continue within a for causes the reinit code to be executed. With both for and while, the condition must still be true before the body will repeat again.

Tcl Procedures

A Tcl procedure is a command defined solely in Tcl. It may use other Tcl procedures or built-in commands to do its work. You may (re)define Tcl procedures whenever you wish using the procproc command. Tcl procedures have three attributes:

22

name This is, of course, the command name which will invoke the procedure.

arg list This is a list of the formal parameters of the procedure. That is, it’s a list of the names by which this procedure will refer to its arguments. The number of arguments passed on the command line must normally match the number of arguments in the list.

body The body is a list of Tcl commands to be executed. It’s just like the bodies of the if, while, etc., statements.

*proc name arg list body

Description

The proc command is used to (re)define a procedure. You always give it three argments: the name, the argument list, and the procedure body. If a procedure (or a built-in) with the specified name already exists, then the old one is deleted and replaced by the new one.

Procedures can return an explicit value by using the return statement. If the last statement of the procedure body is not return, then the result of the procedure will be the result of that statement.

23

That means that the following two procedure definitions produce equivalent results. The first one is slightly slower, but it’s clearer to someone reading the code that it’s intended to return the sum of the two arguments.

proc plus {a b} {return [expr $a + $b]} proc plus {a b} {expr $a + $b}

Either way, you can use the new plus command as follows:

%proc plus {a b} {expr $a + $b}

%plus 2 3

5

%

Notice that the arguments which are written on the command line (2 and 3) are passed to the procedure and it “knows” them by the names a and b.

% plus 2

no value given for parameter "b" to "plus"

% plus 2 3 4

called "plus" with too many arguments

We can also write a procedure which takes a variable number of arguments and returns the sum of all of them, using the keyword args, whose value will be the list of the arguments passed:

% proc sum {args} { set result 0

foreach i $args {incr result $i} return $result

}

% sum 1 2 3 6

%

Notice in the previous example that we used a “helper” variable called result, inside procedure sum. Whenever the set or related commands is used to create a variable inside a procedure, that variable is local to that procedure. That is, its value is independent of any other variables named result in other procedures, and when the procedure returns, this particular variable result and its value will be destroyed. This process is called “going out of scope”—once no code can possibly access that variable, then there’s no need for it any more.

Thus, by default variables in Tcl are local. It is good coding practice to avoid the use of global variables whenever possible.

Global Variables

As we’ve already seen, variables can exist outside the scope of any procedure. These variables are called global, and they can be accessed from within procedures by declaring them with the special keyword global prior to accessing them.

24

Here’s an example of a procedure accessing a global variable x. It accepts one argument a, adds it to the global variables x and y, and returns that result.

%set x 4

4

%set y 5

5

%proc foo {a} { global x y

return [expr $x + $a + $y]

}

%foo 3

12

%set x 6

6

%foo 3

14

Local variables, as well as arguments, are created separately each time a procedure is invoked. This allows writing recursive procedures. Recursive procedures are procedures which may call themselves.

The classic example of a recursive procedure is one to calculate factorials. As you remember, by definition

n! = n × (n − 1) × . . . 1

so we can write a factorial function in Tcl as follows:

% proc fact {x} {

if {$x <= 1} {return 1}

expr $x * [fact [expr $x - 1]]

}

% fact 5 120

%

So far, every example of passing arguments to procedures has been pass by value: that is, the value of the variable is passed to the procedure, which knows that value by its own name. What if, instead, we want to write a procedure which can modify a variable which is passed as an argument?

To do this, or to pass an array as an argument, we need a way to pass arguments by reference. The upvar command allows us to do so. When declaring a procedure which is to receive an argument by reference, use a dummy name to mark the argument, then use upvar to assign this to a local name.

25

Notice that the variable foo is set to a new value by myproc:

% proc myproc {a} { upvar $a myvar

set myvar 4

}

%set foo 3

3

%myproc foo

4

%set foo

4

%

Notice in this example that we can pass a whole associative array as an argument:

% proc array_size {a} { upvar $a myarray

return [array size myarray]

}

%set age(Tim) 37

37

%set age(Siamak) 36

36

%array_size age

2

%

Errors and Exceptions

In older programming languages, all error conditions had to be handled by explicit checking throughout the code. For instance, when you open a file, you have to check the return value to see if the open was successful, and if not, take some action.

An exception is something out of the ordinary which occurs as a program is running. For instance, if you divide by zero, an exception might be raised, and it would usually cause the operating system to abort the execution of your program. Even DOS detects divide by zero exceptions, for example.

Modern thinking on programming languages is that exception and error handling should be concentrated in a few places within a program rather than sprinkled throughout. This has several benefits: primarily, that the code which does the “normal” work is much easier to read and understand (and therefore more likely to work correctly), because it doesn’t have all the exceptional code interspersed.

When a Tcl procedure or built-in wants to raise an exception, it can execute a variation of the return statement to return not only the normal return string (which would probably be an error message of some type), but also an exception (or return) code. A code of 0 is the normal, non-error return. Codes 1, 2, and 3 are used for exception, break, and continue events. Other codes can be defined by the application.

26

When a non-zero return code is returned, Tcl will keep returning the code up the call stack until it either reaches the top level or it reaches a procedure which is prepared to handle an exceptional return.

The Tcl command used to catch exceptional returns is catch. The easiest way to use it is

catch script var

This will execute the command(s) in script. If it and any procedures it calls all return normally, then processing simply passes to the subsequent command. Otherwise, the catch command returns as its value the error code, and var will be set to the error message (string) which was returned from the script.

Amanda Portal is designed to minimize the number of places that an application programmer will need to use catch.

27

Here’s an example of using catch, plus the error which can be used to raise an exception:

proc foo {a} {

if {$a != "bar"} {

error "The argument was invalid"

}

return "Everything ok"

}

proc foo {} {

set code [catch {foo baz} result]

if {$code} {

puts "Error received: $result"

# Pass the error up the stack return -code $code $result

} else {

puts "Execution ok: $result"

}

}

The info command is used to get various pieces of information from the Tcl interpreter. It has many di erent options. The ones which are likely to be of interest are:

args proc Returns the list of arguments for procedure proc.

body proc Returns the body of procedure proc.

commands pattern Lists the built-in and Tcl procedures whose names match pattern. If no pattern is specified, all names are returned.

exists var Returns true if var is currently a valid variable name. You might do this before trying to access its value under some circumstances.

procs pattern This is like commands, but it returns only procedures defined in Tcl (those matching pattern if it’s specified).

tclversion Returns the version number of the interpreter.

vars pattern Like commands, but it returns a list of variables (those matching pattern if it’s specified).

1.2.2Tcl and Multithreading

Tcl originally did not support multithreading in any way. Because Amanda Portal has a need for multiple threads because so many things are happening at once, tAA added multithread safety to Tcl. Upcoming versions of Tcl will include Unicode support for multiple languages and multithread safety; when Tcl 8.1 is released, Amanda Portal will be switched to use that version.

28

The multithreading that was added only allows one thread per interpreter. This is a good thing because the global variables errorCode and errorInfo are per interpreter and should not be shared between threads. Interpreters (and the threads which are tightly bound to them) are spawned o whenever a new “task” needs to be executed. A “task” is spawned for some event such as a call coming in. When a call comes in, for instance, the core creates a new interpreter and a new thread to handle the call. The entry point in the Tcl code can vary depending on configuration parameters used by that DLL.

1.2.3Tcl and State

Tcl allows you to store state in a number of places. You can store state globally, on the stack (local variables) and in arrays. (Sort of. Tcl treats the variable as a single value with respect to scoping but you can store aggregate information in the array.)

Tcl allows you to attach internal state to Tcl functions and interpreters and to install triggers on Tcl variables. Interestingly, internal Tcl state cannot be attached to Tcl variables. Tcl state is attached to functions through the ClientData parameter. This parameter gets set when you create the function. Internal Tcl state is attached to an interpreter with the Tcl SetAssocData() and Tcl GetAssocData() functions. Triggers (called “traces” in Tcl) can be attached to variables that fire o whenever the variable is read, written or deleted.

1.2.4Assigning Scope to Procedures

Procedures in Tcl are not scoped. This is unfortunate because we want to make VP and LS device handles and MMO handles into functions and be able to call the functions in an object-oriented fashion like

$vp play $mmo

which would play the sound associated with the MMO handle on the specified VP device. Since procedures are not scoped, the handles would not disappear if the stack returned. That is,

proc play_greeting {} {

 

grab_res vp vp_proc

;# Get a single VP device. Return new proc name.

# Get greeting 1 from box 10. Return new proc. lookup_mmo -box 10 "Grt 1 English" mmo_proc

$vp_proc play $mmo_proc ;# MMO specific data in ClientData of $mmo_proc.

}

would not delete the procedures named by the values of the variables vp proc and mmo proc when the procedure is done because procedures are not scoped.

29

Loading...
+ 196 hidden pages