Tivoli Service Desk 6.0 Developer's Toolkit Script Programming Guide
This chapter introduces you to the data types used most often in Developer's Toolkit. In addition to discussions of the data types themselves, you can find information about constants, variables, and expressions.
Data types define the properties of data contained in a variable or constant. Possible properties could include:
Developer's Toolkit has six simple data types.
A handle is a variable that contains the address of another variable. An address is the location of a variable. A handle allows a program to access a specific resource.
Handle types have specific uses and are not derived from any other types. Developers use handles to identify a logical entity upon which operations are performed. A list of handle types follows:
External parameter types are annotated versions of simple types that help the Developer's Toolkit Interpreter to convert Developer's Toolkit values to the proper C or Pascal type before calling an external DLL:
The three aggregate types can not stand alone, but can be used in conjunction with any other type to create user-defined types:
Constants are named items that remain unchanged, or constant, throughout the execution of a program. All constant declarations are made in the CONSTANTS section of a knowledgebase.
To declare a constant in a knowledgebase you must:
Constant declarations, like all Developer's Toolkit statements, always end with a semi-colon (;).
Some examples of constant declarations using different data types are shown in this example:
CONSTANTS (* string constants *) fileName IS 'MYFILE.DAT'; pathName IS 'EADVISOR\ADVISOR\DATA'; driveName IS 'E:';
(* integer constants *) MAX_EMPLOYEES IS 500; ERROR_CODE IS -1;
(* real constants *) PI_VALUE IS 3.14159; MAX_SALARY IS 999999.99; LO_VALUE IS -5134.1348;
(* Boolean constants *) SAVE_TO_DISK IS TRUE; OVERWRITE_FILE IS FALSE;
(* date constants *) CHRISTMAS IS {12,25,1996}: DATE; BIRTH_DAY IS {2,13,1956}: DATE;
(* time constants *) START_OF_DAY IS {8,30,0}: TIME; END_OF_DAY IS {18,0,0}: TIME;
Note: International users should be aware that the ordering of date "parts" in a Developer's Toolkit initialization is (month, day, year) and does not change from locale to locale.
Variables are named items that contain data types that can be modified during program execution. Variables are declared in the VARIABLES section of a knowledgebase.
To declare a variable in a knowledgebase you must:
As shown in the following example, you can declare multiple variables of the same type by separating their names with commas:
VARIABLES first_name, last_name : STRING; i,j : INTEGER; salary : REAL; married : BOOLEAN; entryDate : DATE; startTime : TIME;
You assign values to variables with the assignment operator (:=).
The following code fragment shows some variable assignments for the variables that were defined in the preceding example:
first_name := 'Amy'; last_name := 'Alec'; i := 7; j := 32; salary := 37500.00; married := FALSE; entryDate := {1,31,1991}: DATE; startTime := {10,30,0}: TIME;
There may be times when you need to convert data types. Data conversion occurs when there is a change in the way information is represented. For example, you can change binary representation to decimal or hexidecimal representation, or integers to strings.
Developer's Toolkit uses curly braces {}to indicate which value is to be converted.
In this example the value inside the curly braces is converted to an integer:
i := {s}: INTEGER;
When Developer's Toolkit encounters this line, it:
Converting a value does not destroy the original value.
The following is a more complicated example of a data conversion showing how Developer's Toolkit calculates the number of days between two given dates:
d1 := {1,1,1990}: DATE; d2 := $Today; daysBetween = {d2}: INTEGER - {d1}: INTEGER;
To accomplish this, Developer's Toolkit uses the date values stored in {d1} and {d2}, converts them to their Julian values, and subtracts these values.
This example assumes that {d1} and {d2} are date variables and that the variable daysBetween is an integer.
Developer's Toolkit is a strongly typed language, which means that if you assign a variable of one type to a variable of another type, an error occurs.
For example, if you assume that entryDate is a date variable and that startTime is a time variable, the following assignment generates a run-time error:
entryDate := startTime;
Developer's Toolkit converts integers and reals automatically. For example, assuming that the variable i is an integer, the statement
i := 37.0;
causes the value 37 to be assigned to the i variable with no explicit type conversion
necessary.
Likewise if r is a real number, the statement,
r := i;
assigns the value 37.0 to the r variable.
Mixed expressions are treated as real numbers until the assignment is made in order to preserve accuracy.
In addition, Developer's Toolkit automatically converts all data types to strings when necessary. For instance, the statement:
s := i;
assigns the string value 37 to the s variable.
A string in Developer's Toolkit is a sequence of characters surrounded by single quotes. Developer's Toolkit provides string manipulation operators and statements that allow you to perform operations to:
String operators and statements are summarized in the following list.
s1 := 'F:\CODE'; s2 := 'PROGRAM.EXE'; s3 := s1 & '\' & s2;
In this example, the s3 variable contains the string F:\CODE\PROGRAM.EXE.' The s1 and s2 variables have not changed in any way and retain their original values. The ampersand can be used to concatenate any number of constants, variables, or expressions to form a new string. The ampersand also automatically converts non-string values to strings before performing the concatenation. For instance:
s1 := 'The date is ' & $Today & 'and the time is ' & $Now;
In the preceding example, the Developer's Toolkit constants $Today (system date) and $Now (system time) are automatically converted to string forms for the concatenation.
s := 'LIB(ase) FILE(qrpgsrc); s := StrUpper(s); (* now s = 'LIB(ASE) FILE(QRPGSRC) *)
Note: For international users, Developer's Toolkit follows the appropriate upper casing rules for the current locale. For instance, "eclair" becomes "ECLAIR" in France and French-speaking areas of Canada.
s := 'LIB(ase) FILE(qrpgsrc); s := StrLower(s); (* now s = 'lib(ase) file(qrpgsrc) *)
Note: For international users, Developer's Toolkit follows the appropriate case rules for the workstation's current locale.
~ The string variable into which the new string is inserted
~ The string being inserted
~ The index in the string parameter where the new string is to be inserted
For example:
s := StrInsert('LIB(ASE) MBR(MYPROG)', 'FILE(QRPGSRC) ',10); (* now s = 'LIB(ASE) FILE(QRPGSRC) MBR(MYPROG) *)
Note: International users who write code for multiple locales should try to avoid "assembling" sentences from various pieces and parts. The gender and gender agreement that exists in many languages is destroyed when sentences are assembled in this way.
~ The name of a string parameter
~ A starting index
~ The number of characters to be deleted
For example:
s := StrDelete('LIB(ASE) FILE(QRPGSRC) MBR(MYPROG)',10,14); (* now s = 'LIB(ASE) MBR(MYPROG)' *)
~ Name of the source string
~ Starting index within the source string
~ Number of characters to be copied
For example:
fileName := 'LIB(ASE) FILE(QRPGSRC) MBR(MYPROG)'; s := StrCopy(fileName,15,7); (* now S = 'QRPGSRC' *)
Note: The StrPos search is not case-sensitive. The first position is always indexed at 1, rather than 0 as in C and some other programming languages.
If the second string cannot be found, a value of "0" is returned. For instance:
company := 'Tivoli Systems'; loc := StrPos(company, 'Sys'); (*loc = 8*)
The loc variable contains the value 8 after this code executes.
For example:
IF StrMatch(s,'*.BAK') THEN FErase(s); END;
Developer's Toolkit includes other string manipulation including StrToken (a destructive string tokenizer), StrTrim, StrLTrim, and StrLength.
Developer's Toolkit supports arithmetic expressions and operators as summarized in the following table.
Operator Description + Adds two numeric expressions (i:=3+5) - Subtracts one numeric expression from another (r:=3.7-2.0) * Multiplies two numeric expressions (i:=3.0*6) / Divides two numeric expressions (r:=3.0/4.0) MOD Computes the remainder when one integer is divided by another (6 MOD 4=2)
In addition to the operators, Developer's Toolkit supports the following functions:
Trigonometric | Logarithmic | Exponential |
Sin | Log | Exp |
Cos | Ln | Power |
Tan | Sqrt | n/a |
ACos | n/a | n/a |
ASin | n/a | n/a |
ATan | n/a | n/a |
CosH | n/a | n/a |
SinH | n/a | n/a |
TanH | n/a | n/a |
The logical operators AND, OR, and NOT can be used to create complex Boolean expressions such as:
b := (i > 0) AND (j = 0);
Developer's Toolkit performs short-circuited Boolean evaluation. This form of evaluation guarantees that Boolean expressions will be evaluated only as far as necessary to determine their value.
In the example above, if i is 0, the b variable assumes the value of FALSE before j is evaluated. As a rule:
Developer's Toolkit provides the following relational operators for use in Boolean expressions.
Operator | Description |
< | Less than |
<= | Less than or equal |
> | Greater than |
>= | Greater than or equal |
= | Equal |
<> | Not equal |
Note: The relational operators listed above ignore case when comparing two strings. This means that the following expression is TRUE:
'F:\MYFILE' = 'f:\myfile'
The following operators provide for the use of case-sensitive string comparisons.
Operator | Description |
<< | Less than |
<<== | Less than or equal |
>> | Greater than |
>>== | Greater than or equal |
== | Equal to |
<<>> | Not equal |
Refer to the note on the page for an example.
Although considered a simple data type, a date value uses an invisible structure that allows you to obtain month, day, and year values. Use dotted notation as shown in the following example.
dayValue := $Today.day; monthValue := $Today.month; yearValue := $Today.year; (* $Today is the system date*)
As shown, any date expression can be followed with a period and one of the keywords (day, month, or year) that accesses the corresponding value of the date. In the preceding example, dayValue, monthValue, and yearValue are integer variables.
You can change the month, day, or year value of a date variable, as you see here:
d := $Today; d.year := d.year + 1;
In the preceding example a date variable, d, is assigned to the
current system date value. The year for d is then incremented by one.
Developer's Toolkit protects users against invalid dates. In the following example, the
date variable uses a value of "2/1/1999" (not "1/32/1999"):
d := {1,31,1999}: DATE; d.day := d.day + 1;
Developer's Toolkit provides a DateDif function to calculate the difference between two dates in months, days, or years.
DateDif requires three arguments:
For example:
age := DateDif($Today,birthDate,$Years);
Developer's Toolkit provides several facilities that allow you to manipulate time expressions. Like dates, times contain multiple values: hour, minute, and second.
You can use dotted notation (also used in dates) to access the different parts of a time value:
currentHour := $Now.hour; currentMinute := $Now.minute; currentSecond := $Now.second; (* $Now is the system time*)
You can also change a specific part of a time variable:
t := $Now; t.hour := t.hour + 3;
The time variable, t, contains the value of the time three hours from now. Time values have an internal 24-hour format that allows for midnight. The result of the following example is t containing the value {1,0,0}:TIME or one A.M.:
t := {23,0,0}: TIME; t.hour := t.hour + 2;
Developer's Toolkit provides a TimeDif function that calculates the difference between two times. The following example computes the difference between the current time and a previous startTime in hours, minutes, and seconds:
hoursDiff := TimeDif($Now,startTime,$Hours); minutesDiff := TimeDif($Now,startTime,$Minutes); secondsDiff := TimeDif($Now,startTime,$Seconds);
An array is a list of data values of the same data type. It is also a structured data type. Structured data types allow specific operations to be performed on the data.
Any single element (data value) in an array can be referenced by an expression composed of the name of the array followed by an index expression. Elements in an array are sequential, beginning with one (1). To access a specific element, the value, or index, is used.
In the following example, each index is enclosed in square brackets:
VARIABLES name[10]: ARRAY OF String; ACTIONS name[1] := 'Tom'; name[2] := 'Dick'; name[3] := 'Harry';
In this example, name is an array of strings. The name variable can hold up to ten string values in elements numbered 1 through 10.
Arrays are commonly accessed with variables. The following example shows how integer variable i is used to access a given array element writing all ten values of the name array to a file:
FOR i := 1 TO 10 DO FWriteLN(outputFile,name[i]); END;
An attempt to access an array element outside the defined limits of the array causes a runtime error message to appear. Errors will be generated by both of these statements:
name[-1] := 'Dick'; name[45] := 'Harry';
String values can be treated as arrays of characters. At the end of the following code example, the s variable has the value G:\EADVISOR\ADVISOR\DATA.
VARIABLES s : STRING; ACTIONS s := 'F:\EADVISOR\ADVISOR\DATA'; s[1] := 'G';
Developer's Toolkit arrays are dynamically resizable. That is, you can change the size of an array at runtime. The Developer's Toolkit statement SetArrayLength is used to change the size of any array. For example,
SetArrayLength(name,100);
would add 90 new elements to the ten-slot array previously declared. None of the information in the first ten slots would be affected. You can also decrease the size of an array as shown in this example:
SetArrayLength(name,5);
In this case, any values in slots 6 through 10 would be lost.
Similar to an array, a Developer's Toolkit list is a structured data type that can contain multiple values of the same type. Lists can also be indexed with an integer enclosed in square brackets.
In Developer's Toolkit, you do not need addresses, memory allocation, or memory deallocation to create complete linked-list structures. Lists can be sized more easily than arrays. Also, you can insert a new value in the middle of a list, which is an awkward process in an array.
The following example shows how to declare and use lists:
VARIABLES name: List of String; ACTIONS ListInsert(name,'Tom'); ListInsert(name,'Dick'); ListInsert(name,'Harry');
At the conclusion of this code example, name is a list containing three values: 'Tom', 'Dick', and 'Harry'.
Every list maintains a pointer that indicates the current element in a list. This is called the list pointer. When a new element is inserted into a list, the list pointer indicates the newly inserted element. At the end of the previous example, the current pointer points to 'Harry'.
The next example shows how to insert a new element in the middle of the preceding list.
ListSetPos(name,1); ListInsert(name,'Ellen');
Name now contains four values: 'Tom,' 'Ellen,' 'Dick,' and 'Harry'.
Note: 'Ellen' is in the second position because $ListInsert defaults to $After.The list pointer points to 'Ellen.' ListSetPos moves the list pointer to a given element.
Developer's Toolkit provides a number of other functions that allow you to manipulate lists.
Function | Description |
ListDelete | Removes an element from a list. (ListDelete(name,2) removes 'Ellen' from the previous example). |
ListLength | Returns the number of elements in the list. |
ListNext | Moves the pointer to the next element in the list. |
ListPrev | Moves the pointer to the previous element in the list. |
ListPos | Returns the index of the current element. |
ListFind | Scans the list for a given value and returns TRUE if that value is found. The list pointer is moved to the matching value. For example, ListFind(name,'Dick') returns TRUE and moves the current pointer to 'Dick.' |
ListSort | Sorts the list in ascending order. |
ListPush | Adds a new element to the front of the list. |
ListPop | Removes the first element in the list and returns it. |
Because lists can be indexed like arrays, the statement,
s:= name[1];
assigns the value 'Tom' to the s variable.
Developer's Toolkit provides a special looping construct for lists. The FOR statement is used to iterate through values in a list. Statements nested in the FOR...END block are executed once for each element in the list. The list pointer always points to the first number in the list. The current item in the list is incremented by one on each pass through the loop.
The following example illustrates the use of the FOR statement:
FOR name DO FWriteLN(outputFile,name[$Current]); END;
The previous example also illustrates the use of a special constant called $Current. This constant can be used to access the current elements of a list. Other list constants include:
These constants are used to access the first and last elements of the list, respectively. For example, the lines,
FWriteLN(outputFile,name[$First]); FWriteLN(outputFile,name[$Last]);
would write "Tom" and "Harry" to the output file.
Many Developer's Toolkit statements support automatic list "chunking." In list chunking, the statements accept either a single item of a given type or a list of items.
If you pass a list, the statement applies to all the elements in the list. This is also referred to as a statement with an implicit FOR loop.
WinWriteLN is an example of one such statement:
WinWriteLN(myWindow,name);
This statement causes every value of the variable name to be written to the window referred to as myWindow. Several of the Window statements and SQL statements support list chunking.
Unlike arrays and lists, which can hold multiple values of the same type, a record can hold multiple values of different types.
Declaring a record-type variable is a two step process:
Note: When you declare a record type variable, you are extending the Developer's Toolkit language with your own data type.
Examine the following code example:
TYPES EmployeeRecord IS RECORD first_name, last_name: String; age : Integer; salary : Real; married : Boolean; hireDate : Date; startTime, stopTime : Time; END; VARIABLES employee: EmployeeRecord;
The preceding example declares a new record type called EmployeeRecord. This record contains eight fields, each of which is a simple data type.
As with dates and times, you can use a <variable>.<field> (dotted) notation
to reference any of the fields in a record.
For example, the following lines can be used to initialize the employee variable declared
previously:
employee.first_name := 'Calbert'; employee.last_name := 'Chaney'; employee.age := 21; employee.salary := 2500000.0; employee.married := FALSE; employee.hireDate := {2,15,1993}: DATE; employee.startTime := {8,30,0}: TIME; employee.stopTime := {17,30,0}: TIME;
Variables of the same record type are assignment-compatible. If you declared a variable, employee2, of type EmployeeRecord, adding the following statement would result in all fields of the employee variable being copied into the employee2 variable:
employee2 := employee;
You can also create lists and arrays of records:
employeeList: List Of EmployeeRecord;
A record declaration can contain arrays, lists, and other records. For example, the EmployeeRecord declaration could be altered in the following way:
EmployeeRecord IS RECORD first_name, last_name: String; age : Integer; salary : Real; married : Boolean; hireDate : Date; startTime, stopTime : Time; manages : List of String; END;
The manages value might be used to keep track of the names of employees managed by a given employee.
Developer's Toolkit provides several statements that perform database record input and output.
For example, the following statement could be used to load a row from the EMPLOYEES table into the employee variable declared previously:
SQLSelectInto('SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID=105',employee);
Developer's Toolkit:
Similarly, the Developer's Toolkit allows you to map the fields in a record onto a form. When a user presses the ENTER key after completing a form, the information on the screen is saved into corresponding fields in the record that can be examined and manipulated.
In addition to records, you can create other user-defined types. A user-defined type is a data type that is defined in a program and usually consists of a combination of data types. User-defined types are often used to create data structures.
Any combination of lists, arrays, records, and simple data types you use in a variable declaration can be given a reusable name in a data type declaration. For instance, you might define a new data type as shown in the following example:
TYPES StringList = LIST OF STRING;
Once declared, you can use StringList to declare variables instead of LIST OF STRING.
The following rules refer to assignment compatibility of user-defined and structured data types.
When checking for assignment compatibility between two variables or expressions, Developer's Toolkit only checks to see if the type names match. It does not check to see if the record declarations are identical.
Initializing a declared variable means that an initial value is assigned to it. Developer's Toolkit allows you to initialize variables when they are declared, as shown in the following example:
VARIABLES i {1} : INTEGER; s {'F:\MYFILE'} : STRING; d {2,11,1956} : DATE; l {'Tom','Dick','Harry'} : LIST OF STRING; r {'Steve','Wantz',32,189000.00,TRUE, {3,30,1986} : DATE, {6,30,0} : TIME, {4,30,0} : TIME, {'Tom','Dick','Harry'} : LIST OF STRING : EmployeeRecord;
In general, a variable name is followed by:
You can also initialize variables of structured types like lists, arrays, and records in the same way.
Note that the initialization value is associated with the variable and not the type. So in the line,
VARIABLES i, j {27}: INTEGER;
only the j variable is initialized; the i variable is not. Each variable must be initialized separately.
All non-initialized variables that have no value in Developer's Toolkit start with a value of $Unknown. This is different from C and Pascal, where variables begin with random values.
Initializing all variables to zero, one, or an empty string protects against common errors. For example, if in the following:
newSalary := oldSalary*1.05;
the variable oldSalary was not initialized to something other than $Unknown, an error would occur at run time because 1.05 would be multiplied by $Unknown.
Tivoli Service Desk 6.0 Developer's Toolkit Script Programming Guide